Merge branch 'master' of github.com:highfidelity/hifi into qml-keyboard

This commit is contained in:
Seth Alves 2016-09-10 10:43:07 -07:00
commit 8899c0b790
45 changed files with 774 additions and 276 deletions

View file

@ -74,6 +74,13 @@ else ()
endif () endif ()
endif(WIN32) endif(WIN32)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.3")
# GLM 0.9.8 on Ubuntu 14 (gcc 4.4) has issues with the simd declarations
add_definitions(-DGLM_FORCE_PURE)
endif()
endif()
if (NOT ANDROID) if (NOT ANDROID)
if ((NOT MSVC12) AND (NOT MSVC14)) if ((NOT MSVC12) AND (NOT MSVC14))
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)

21
cmake/externals/gli/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,21 @@
set(EXTERNAL_NAME gli)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://hifi-public.s3.amazonaws.com/dependencies/gli-0.8.1.0.zip
URL_MD5 00c990f59c12bbf367956ef399d6f798
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR} CACHE PATH "List of gli include directories")

View file

@ -3,8 +3,8 @@ set(EXTERNAL_NAME glm)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.5.4.zip URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip
URL_MD5 fab76fc982b256b46208e5c750ed456a URL_MD5 579ac77a3110befa3244d68c0ceb7281
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
LOG_DOWNLOAD 1 LOG_DOWNLOAD 1

View file

@ -0,0 +1,12 @@
#
# Copyright 2015 High Fidelity, Inc.
# Created by Bradley Austin Davis on 2015/10/10
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(TARGET_GLI)
add_dependency_external_projects(gli)
find_package(GLI REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLI_INCLUDE_DIRS})
endmacro()

View file

@ -0,0 +1,26 @@
#
# FindGLI.cmake
#
# Try to find GLI include path.
# Once done this will define
#
# GLI_INCLUDE_DIRS
#
# Created on 2016/09/03 by Bradley Austin Davis
# 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
#
# setup hints for GLI search
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("gli")
# locate header
find_path(GLI_INCLUDE_DIRS "gli/gli.hpp" HINTS ${GLI_SEARCH_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GLI DEFAULT_MSG GLI_INCLUDE_DIRS)
mark_as_advanced(GLI_INCLUDE_DIRS GLI_SEARCH_DIRS)

View file

@ -2006,7 +2006,7 @@ void Application::resizeGL() {
static qreal lastDevicePixelRatio = 0; static qreal lastDevicePixelRatio = 0;
qreal devicePixelRatio = _window->devicePixelRatio(); qreal devicePixelRatio = _window->devicePixelRatio();
if (offscreenUi->size() != fromGlm(uiSize) || devicePixelRatio != lastDevicePixelRatio) { if (offscreenUi->size() != fromGlm(uiSize) || devicePixelRatio != lastDevicePixelRatio) {
qDebug() << "Device pixel ratio changed, triggering resize"; qDebug() << "Device pixel ratio changed, triggering resize to " << uiSize;
offscreenUi->resize(fromGlm(uiSize), true); offscreenUi->resize(fromGlm(uiSize), true);
_offscreenContext->makeCurrent(); _offscreenContext->makeCurrent();
lastDevicePixelRatio = devicePixelRatio; lastDevicePixelRatio = devicePixelRatio;
@ -3288,7 +3288,7 @@ void Application::init() {
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) { getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
auto dims = item.getDimensions(); auto dims = item.getDimensions();
auto maxSize = glm::max(dims.x, dims.y, dims.z); auto maxSize = glm::compMax(dims);
if (maxSize <= 0.0f) { if (maxSize <= 0.0f) {
return 0.0f; return 0.0f;

View file

@ -47,6 +47,8 @@
#include "Menu.h" #include "Menu.h"
extern bool DEV_DECIMATE_TEXTURES;
Menu* Menu::getInstance() { Menu* Menu::getInstance() {
return dynamic_cast<Menu*>(qApp->getWindow()->menuBar()); return dynamic_cast<Menu*>(qApp->getWindow()->menuBar());
} }
@ -390,6 +392,14 @@ Menu::Menu() {
// Developer > Render > LOD Tools // Developer > Render > LOD Tools
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, dialogsManager.data(), SLOT(lodTools())); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, dialogsManager.data(), SLOT(lodTools()));
// HACK enable texture decimation
{
auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, "Decimate Textures");
connect(action, &QAction::triggered, [&](bool checked) {
DEV_DECIMATE_TEXTURES = checked;
});
}
// Developer > Assets >>> // Developer > Assets >>>
MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets"); MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets");
auto& atpMigrator = ATPAssetMigrator::getInstance(); auto& atpMigrator = ATPAssetMigrator::getInstance();

View file

@ -55,7 +55,7 @@ void SoftAttachmentModel::updateClusterMatrices(glm::vec3 modelPosition, glm::qu
// TODO: cache these look ups as an optimization // TODO: cache these look ups as an optimization
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); int jointIndexOverride = getJointIndexOverride(cluster.jointIndex);
glm::mat4 jointMatrix(glm::mat4::_null); glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride->getJointStateCount()) { if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride->getJointStateCount()) {
jointMatrix = _rigOverride->getJointTransform(jointIndexOverride); jointMatrix = _rigOverride->getJointTransform(jointIndexOverride);
} else { } else {

View file

@ -277,6 +277,17 @@ void setupPreferences() {
preference->setStep(1); preference->setStep(1);
preferences->addPreference(preference); preferences->addPreference(preference);
} }
#if DEV_BUILD || PR_BUILD
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getGateThreshold(); };
auto setter = [](float value) { return DependencyManager::get<AudioClient>()->setGateThreshold(value); };
auto preference = new SpinnerPreference(AUDIO, "Debug gate threshold", getter, setter);
preference->setMin(1);
preference->setMax((float)100);
preference->setStep(1);
preferences->addPreference(preference);
}
#endif
{ {
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); }; auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };

View file

@ -1093,7 +1093,7 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
// prevent the hand IK targets from intersecting the body capsule // prevent the hand IK targets from intersecting the body capsule
glm::vec3 handPosition = params.leftPosition; glm::vec3 handPosition = params.leftPosition;
glm::vec3 displacement(glm::vec3::_null); glm::vec3 displacement;
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) { if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) {
handPosition -= displacement; handPosition -= displacement;
} }
@ -1111,7 +1111,7 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
// prevent the hand IK targets from intersecting the body capsule // prevent the hand IK targets from intersecting the body capsule
glm::vec3 handPosition = params.rightPosition; glm::vec3 handPosition = params.rightPosition;
glm::vec3 displacement(glm::vec3::_null); glm::vec3 displacement;
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) { if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) {
handPosition -= displacement; handPosition -= displacement;
} }

View file

@ -55,6 +55,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100;
static const auto DEFAULT_POSITION_GETTER = []{ return Vectors::ZERO; }; static const auto DEFAULT_POSITION_GETTER = []{ return Vectors::ZERO; };
static const auto DEFAULT_ORIENTATION_GETTER = [] { return Quaternions::IDENTITY; }; static const auto DEFAULT_ORIENTATION_GETTER = [] { return Quaternions::IDENTITY; };
static const int DEFAULT_AUDIO_OUTPUT_GATE_THRESHOLD = 1;
Setting::Handle<bool> dynamicJitterBuffers("dynamicJitterBuffers", DEFAULT_DYNAMIC_JITTER_BUFFERS); Setting::Handle<bool> dynamicJitterBuffers("dynamicJitterBuffers", DEFAULT_DYNAMIC_JITTER_BUFFERS);
Setting::Handle<int> maxFramesOverDesired("maxFramesOverDesired", DEFAULT_MAX_FRAMES_OVER_DESIRED); Setting::Handle<int> maxFramesOverDesired("maxFramesOverDesired", DEFAULT_MAX_FRAMES_OVER_DESIRED);
Setting::Handle<int> staticDesiredJitterBufferFrames("staticDesiredJitterBufferFrames", Setting::Handle<int> staticDesiredJitterBufferFrames("staticDesiredJitterBufferFrames",
@ -99,6 +101,8 @@ private:
AudioClient::AudioClient() : AudioClient::AudioClient() :
AbstractAudioInterface(), AbstractAudioInterface(),
_gateThreshold("audioOutputGateThreshold", DEFAULT_AUDIO_OUTPUT_GATE_THRESHOLD),
_gate(this, _gateThreshold.get()),
_audioInput(NULL), _audioInput(NULL),
_desiredInputFormat(), _desiredInputFormat(),
_inputFormat(), _inputFormat(),
@ -540,11 +544,48 @@ void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message)
emit receivedFirstPacket(); emit receivedFirstPacket();
} }
#if DEV_BUILD || PR_BUILD
_gate.insert(message);
#else
// Audio output must exist and be correctly set up if we're going to process received audio // Audio output must exist and be correctly set up if we're going to process received audio
_receivedAudioStream.parseData(*message); _receivedAudioStream.parseData(*message);
#endif
} }
} }
AudioClient::Gate::Gate(AudioClient* audioClient, int threshold) :
_audioClient(audioClient),
_threshold(threshold) {}
void AudioClient::Gate::setThreshold(int threshold) {
flush();
_threshold = std::max(threshold, 1);
}
void AudioClient::Gate::insert(QSharedPointer<ReceivedMessage> message) {
// Short-circuit for normal behavior
if (_threshold == 1) {
_audioClient->_receivedAudioStream.parseData(*message);
return;
}
_queue.push(message);
_index++;
if (_index % _threshold == 0) {
flush();
}
}
void AudioClient::Gate::flush() {
while (!_queue.empty()) {
_audioClient->_receivedAudioStream.parseData(*_queue.front());
_queue.pop();
}
_index = 0;
}
void AudioClient::handleNoisyMutePacket(QSharedPointer<ReceivedMessage> message) { void AudioClient::handleNoisyMutePacket(QSharedPointer<ReceivedMessage> message) {
if (!_muted) { if (!_muted) {
toggleMute(); toggleMute();

View file

@ -16,6 +16,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <mutex> #include <mutex>
#include <queue>
#include <QtCore/qsystemdetection.h> #include <QtCore/qsystemdetection.h>
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
@ -134,6 +135,9 @@ public:
int getOutputStarveDetectionThreshold() { return _outputStarveDetectionThreshold.get(); } int getOutputStarveDetectionThreshold() { return _outputStarveDetectionThreshold.get(); }
void setOutputStarveDetectionThreshold(int threshold) { _outputStarveDetectionThreshold.set(threshold); } void setOutputStarveDetectionThreshold(int threshold) { _outputStarveDetectionThreshold.set(threshold); }
int getGateThreshold() { return _gate.getThreshold(); }
void setGateThreshold(int threshold) { _gate.setThreshold(threshold); }
void setPositionGetter(AudioPositionGetter positionGetter) { _positionGetter = positionGetter; } void setPositionGetter(AudioPositionGetter positionGetter) { _positionGetter = positionGetter; }
void setOrientationGetter(AudioOrientationGetter orientationGetter) { _orientationGetter = orientationGetter; } void setOrientationGetter(AudioOrientationGetter orientationGetter) { _orientationGetter = orientationGetter; }
@ -227,6 +231,27 @@ private:
float azimuthForSource(const glm::vec3& relativePosition); float azimuthForSource(const glm::vec3& relativePosition);
float gainForSource(float distance, float volume); float gainForSource(float distance, float volume);
class Gate {
public:
Gate(AudioClient* audioClient, int threshold);
int getThreshold() { return _threshold; }
void setThreshold(int threshold);
void insert(QSharedPointer<ReceivedMessage> message);
private:
void flush();
AudioClient* _audioClient;
std::queue<QSharedPointer<ReceivedMessage>> _queue;
int _index{ 0 };
int _threshold;
};
Setting::Handle<int> _gateThreshold;
Gate _gate;
Mutex _injectorsMutex; Mutex _injectorsMutex;
QByteArray firstInputFrame; QByteArray firstInputFrame;
QAudioInput* _audioInput; QAudioInput* _audioInput;

View file

@ -26,7 +26,7 @@
#include "SoundCache.h" #include "SoundCache.h"
#include "AudioSRC.h" #include "AudioSRC.h"
int audioInjectorPtrMetaTypeId = qRegisterMetaType<AudioInjector*>(); //int audioInjectorPtrMetaTypeId = qRegisterMetaType<AudioInjector*>();
AudioInjectorState operator& (AudioInjectorState lhs, AudioInjectorState rhs) { AudioInjectorState operator& (AudioInjectorState lhs, AudioInjectorState rhs) {
return static_cast<AudioInjectorState>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs)); return static_cast<AudioInjectorState>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));

View file

@ -12,3 +12,9 @@
#include "AudioLogging.h" #include "AudioLogging.h"
Q_LOGGING_CATEGORY(audio, "hifi.audio") Q_LOGGING_CATEGORY(audio, "hifi.audio")
#if DEV_BUILD || PR_BUILD
Q_LOGGING_CATEGORY(audiostream, "hifi.audio-stream", QtDebugMsg)
#else
Q_LOGGING_CATEGORY(audiostream, "hifi.audio-stream", QtInfoMsg)
#endif

View file

@ -15,5 +15,6 @@
#include <QLoggingCategory> #include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(audio) Q_DECLARE_LOGGING_CATEGORY(audio)
Q_DECLARE_LOGGING_CATEGORY(audiostream)
#endif // hifi_AudioLogging_h #endif // hifi_AudioLogging_h

View file

@ -16,6 +16,7 @@
#include <NodeList.h> #include <NodeList.h>
#include "InboundAudioStream.h" #include "InboundAudioStream.h"
#include "AudioLogging.h"
const int STARVE_HISTORY_CAPACITY = 50; const int STARVE_HISTORY_CAPACITY = 50;
@ -174,6 +175,9 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
_currentJitterBufferFrames = 0; _currentJitterBufferFrames = 0;
_oldFramesDropped += framesToDrop; _oldFramesDropped += framesToDrop;
qCDebug(audiostream, "Dropped %d frames", framesToDrop);
qCDebug(audiostream, "Resetted current jitter frames");
} }
framesAvailableChanged(); framesAvailableChanged();
@ -228,6 +232,9 @@ int InboundAudioStream::writeDroppableSilentSamples(int silentSamples) {
_currentJitterBufferFrames -= numSilentFramesToDrop; _currentJitterBufferFrames -= numSilentFramesToDrop;
_silentFramesDropped += numSilentFramesToDrop; _silentFramesDropped += numSilentFramesToDrop;
qCDebug(audiostream, "Dropped %d silent frames", numSilentFramesToDrop);
qCDebug(audiostream, "Set current jitter frames to %d", _currentJitterBufferFrames);
_framesAvailableStat.reset(); _framesAvailableStat.reset();
} }
@ -308,6 +315,8 @@ void InboundAudioStream::framesAvailableChanged() {
if (_framesAvailableStat.getElapsedUsecs() >= FRAMES_AVAILABLE_STAT_WINDOW_USECS) { if (_framesAvailableStat.getElapsedUsecs() >= FRAMES_AVAILABLE_STAT_WINDOW_USECS) {
_currentJitterBufferFrames = (int)ceil(_framesAvailableStat.getAverage()); _currentJitterBufferFrames = (int)ceil(_framesAvailableStat.getAverage());
qCDebug(audiostream, "Set current jitter frames to %d", _currentJitterBufferFrames);
_framesAvailableStat.reset(); _framesAvailableStat.reset();
} }
} }
@ -355,6 +364,7 @@ void InboundAudioStream::setToStarved() {
// make sure _desiredJitterBufferFrames does not become lower here // make sure _desiredJitterBufferFrames does not become lower here
if (calculatedJitterBufferFrames >= _desiredJitterBufferFrames) { if (calculatedJitterBufferFrames >= _desiredJitterBufferFrames) {
_desiredJitterBufferFrames = calculatedJitterBufferFrames; _desiredJitterBufferFrames = calculatedJitterBufferFrames;
qCDebug(audiostream, "Set desired jitter frames to %d", _desiredJitterBufferFrames);
} }
} }
} }
@ -444,6 +454,7 @@ void InboundAudioStream::packetReceivedUpdateTimingStats() {
/ (float)AudioConstants::NETWORK_FRAME_USECS); / (float)AudioConstants::NETWORK_FRAME_USECS);
if (calculatedJitterBufferFrames < _desiredJitterBufferFrames) { if (calculatedJitterBufferFrames < _desiredJitterBufferFrames) {
_desiredJitterBufferFrames = calculatedJitterBufferFrames; _desiredJitterBufferFrames = calculatedJitterBufferFrames;
qCDebug(audiostream, "Set desired jitter frames to %d", _desiredJitterBufferFrames);
} }
_timeGapStatsForDesiredReduction.clearNewStatsAvailableFlag(); _timeGapStatsForDesiredReduction.clearNewStatsAvailableFlag();
} }

View file

@ -33,7 +33,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
glm::vec3 position = getPosition(); glm::vec3 position = getPosition();
glm::vec3 dimensions = getDimensions(); glm::vec3 dimensions = getDimensions();
glm::quat rotation = getRotation(); glm::quat rotation = getRotation();
float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); float largestDiameter = glm::compMax(dimensions);
glm::vec3 color = toGlm(getXColor()); glm::vec3 color = toGlm(getXColor());

View file

@ -299,7 +299,7 @@ bool RenderableModelEntityItem::getAnimationFrame() {
if (index < translations.size()) { if (index < translations.size()) {
translationMat = glm::translate(translations[index]); translationMat = glm::translate(translations[index]);
} }
glm::mat4 rotationMat(glm::mat4::_null); glm::mat4 rotationMat;
if (index < rotations.size()) { if (index < rotations.size()) {
rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation); rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation);
} else { } else {

View file

@ -447,7 +447,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
// set ray cast length to long enough to cover all of the voxel space // set ray cast length to long enough to cover all of the voxel space
float distanceToEntity = glm::distance(origin, getPosition()); float distanceToEntity = glm::distance(origin, getPosition());
glm::vec3 dimensions = getDimensions(); glm::vec3 dimensions = getDimensions();
float largestDimension = glm::max(dimensions.x, dimensions.y, dimensions.z) * 2.0f; float largestDimension = glm::compMax(dimensions) * 2.0f;
glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension); glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f); glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);

View file

@ -15,7 +15,6 @@
#include <stdint.h> #include <stdint.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtx/extented_min_max.hpp>
#include <QtScript/QScriptEngine> #include <QtScript/QScriptEngine>
#include <QtCore/QObject> #include <QtCore/QObject>
@ -221,7 +220,7 @@ public:
public: public:
float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); } float getMaxDimension() const { return glm::compMax(_dimensions); }
float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); } bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); }

View file

@ -49,7 +49,7 @@ void LightEntityItem::setDimensions(const glm::vec3& value) {
const float width = length * glm::sin(glm::radians(_cutoff)); const float width = length * glm::sin(glm::radians(_cutoff));
EntityItem::setDimensions(glm::vec3(width, width, length)); EntityItem::setDimensions(glm::vec3(width, width, length));
} else { } else {
float maxDimension = glm::max(value.x, value.y, value.z); float maxDimension = glm::compMax(value);
EntityItem::setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); EntityItem::setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
} }
} }
@ -82,7 +82,7 @@ void LightEntityItem::setIsSpotlight(bool value) {
const float width = length * glm::sin(glm::radians(_cutoff)); const float width = length * glm::sin(glm::radians(_cutoff));
setDimensions(glm::vec3(width, width, length)); setDimensions(glm::vec3(width, width, length));
} else { } else {
float maxDimension = glm::max(dimensions.x, dimensions.y, dimensions.z); float maxDimension = glm::compMax(dimensions);
setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
} }
} }

View file

@ -4,6 +4,7 @@ link_hifi_libraries(shared gl gpu)
GroupSources("src") GroupSources("src")
target_opengl() target_opengl()
target_nsight()
if (NOT ANDROID) if (NOT ANDROID)
target_glew() target_glew()

View file

@ -315,7 +315,6 @@ void GLBackend::render(const Batch& batch) {
void GLBackend::syncCache() { void GLBackend::syncCache() {
recycle();
syncTransformStateCache(); syncTransformStateCache();
syncPipelineStateCache(); syncPipelineStateCache();
syncInputStateCache(); syncInputStateCache();

View file

@ -9,6 +9,8 @@
#include <mutex> #include <mutex>
#include <QtCore/QThread>
#include <GPUIdent.h> #include <GPUIdent.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <fstream> #include <fstream>
@ -933,9 +935,28 @@ void makeProgramBindings(ShaderObject& shaderObject) {
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
void serverWait() {
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
assert(fence);
glWaitSync(fence, 0, GL_TIMEOUT_IGNORED);
glDeleteSync(fence);
}
void clientWait() {
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
assert(fence);
auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
// Minimum sleep
QThread::usleep(1);
result = glClientWaitSync(fence, 0, 0);
}
glDeleteSync(fence);
}
} } } }
using namespace gpu; using namespace gpu;

View file

@ -18,6 +18,12 @@ Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
namespace gpu { namespace gl { namespace gpu { namespace gl {
// Create a fence and inject a GPU wait on the fence
void serverWait();
// Create a fence and synchronously wait on the fence
void clientWait();
gpu::Size getDedicatedMemory(); gpu::Size getDedicatedMemory();
ComparisonFunction comparisonFuncFromGL(GLenum func); ComparisonFunction comparisonFuncFromGL(GLenum func);
State::StencilOp stencilOpFromGL(GLenum stencilOp); State::StencilOp stencilOpFromGL(GLenum stencilOp);

View file

@ -292,3 +292,14 @@ void GLTexture::postTransfer() {
void GLTexture::initTextureTransferHelper() { void GLTexture::initTextureTransferHelper() {
_textureTransferHelper = std::make_shared<GLTextureTransferHelper>(); _textureTransferHelper = std::make_shared<GLTextureTransferHelper>();
} }
void GLTexture::startTransfer() {
createTexture();
}
void GLTexture::finishTransfer() {
if (_gpuObject.isAutogenerateMips()) {
generateMips();
}
}

View file

@ -11,6 +11,7 @@
#include "GLShared.h" #include "GLShared.h"
#include "GLTextureTransfer.h" #include "GLTextureTransfer.h"
#include "GLBackend.h" #include "GLBackend.h"
#include "GLTexelFormat.h"
namespace gpu { namespace gl { namespace gpu { namespace gl {
@ -19,6 +20,7 @@ struct GLFilterMode {
GLint magFilter; GLint magFilter;
}; };
class GLTexture : public GLObject<Texture> { class GLTexture : public GLObject<Texture> {
public: public:
static const uint16_t INVALID_MIP { (uint16_t)-1 }; static const uint16_t INVALID_MIP { (uint16_t)-1 };
@ -162,11 +164,13 @@ public:
bool isOverMaxMemory() const; bool isOverMaxMemory() const;
protected: uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
static const size_t CUBE_NUM_FACES = 6; static const size_t CUBE_NUM_FACES = 6;
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 const std::vector<GLenum>& getFaceTargets(GLenum textureType);
@ -185,13 +189,11 @@ protected:
GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, GLTexture* originalTexture); 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; }
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
void createTexture(); void createTexture();
virtual void allocateStorage() const = 0; virtual void allocateStorage() const = 0;
virtual void updateSize() const = 0; virtual void updateSize() const = 0;
virtual void transfer() 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 = 0;
@ -199,6 +201,11 @@ protected:
protected: protected:
void setSize(GLuint size) const; void setSize(GLuint size) const;
virtual void startTransfer();
// Returns true if this is the last block required to complete transfer
virtual bool continueTransfer() { return false; }
virtual void finishTransfer();
private: private:
GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable); GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable);

View file

@ -13,6 +13,18 @@
#include "GLShared.h" #include "GLShared.h"
#include "GLTexture.h" #include "GLTexture.h"
#ifdef HAVE_NSIGHT
#include "nvToolsExt.h"
std::unordered_map<TexturePointer, nvtxRangeId_t> _map;
#endif
//#define TEXTURE_TRANSFER_PBOS
#ifdef TEXTURE_TRANSFER_PBOS
#define TEXTURE_TRANSFER_BLOCK_SIZE (64 * 1024)
#define TEXTURE_TRANSFER_PBO_COUNT 128
#endif
using namespace gpu; using namespace gpu;
using namespace gpu::gl; using namespace gpu::gl;
@ -36,82 +48,126 @@ GLTextureTransferHelper::~GLTextureTransferHelper() {
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);
Backend::incrementTextureGPUTransferCount();
#ifdef THREADED_TEXTURE_TRANSFER
GLsync fence { 0 };
//fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
//glFlush();
TextureTransferPackage package { texturePointer, fence }; #ifdef THREADED_TEXTURE_TRANSFER
Backend::incrementTextureGPUTransferCount();
object->setSyncState(GLSyncState::Pending); object->setSyncState(GLSyncState::Pending);
queueItem(package); Lock lock(_mutex);
_pendingTextures.push_back(texturePointer);
#else #else
object->withPreservedTexture([&] { for (object->startTransfer(); object->continueTransfer(); ) { }
do_transfer(*object); object->finishTransfer();
});
object->_contentStamp = texturePointer->getDataStamp(); object->_contentStamp = texturePointer->getDataStamp();
object->setSyncState(GLSyncState::Transferred); object->setSyncState(GLSyncState::Transferred);
#endif #endif
} }
void GLTextureTransferHelper::setup() { void GLTextureTransferHelper::setup() {
#ifdef THREADED_TEXTURE_TRANSFER
_context.makeCurrent();
glCreateRenderbuffers(1, &_drawRenderbuffer);
glNamedRenderbufferStorage(_drawRenderbuffer, GL_RGBA8, 128, 128);
glCreateFramebuffers(1, &_drawFramebuffer);
glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _drawRenderbuffer);
glCreateFramebuffers(1, &_readFramebuffer);
#ifdef TEXTURE_TRANSFER_PBOS
std::array<GLuint, TEXTURE_TRANSFER_PBO_COUNT> pbos;
glCreateBuffers(TEXTURE_TRANSFER_PBO_COUNT, &pbos[0]);
for (uint32_t i = 0; i < TEXTURE_TRANSFER_PBO_COUNT; ++i) {
TextureTransferBlock newBlock;
newBlock._pbo = pbos[i];
glNamedBufferStorage(newBlock._pbo, TEXTURE_TRANSFER_BLOCK_SIZE, 0, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
newBlock._mapped = glMapNamedBufferRange(newBlock._pbo, 0, TEXTURE_TRANSFER_BLOCK_SIZE, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
_readyQueue.push(newBlock);
}
#endif
#endif
} }
void GLTextureTransferHelper::shutdown() { void GLTextureTransferHelper::shutdown() {
}
void GLTextureTransferHelper::do_transfer(GLTexture& texture) {
texture.createTexture();
texture.transfer();
texture.updateSize();
Backend::decrementTextureGPUTransferCount();
}
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
#ifdef THREADED_TEXTURE_TRANSFER #ifdef THREADED_TEXTURE_TRANSFER
_context.makeCurrent(); _context.makeCurrent();
glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0);
glDeleteFramebuffers(1, &_drawFramebuffer);
_drawFramebuffer = 0;
glDeleteFramebuffers(1, &_readFramebuffer);
_readFramebuffer = 0;
glNamedFramebufferTexture(_readFramebuffer, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0);
glDeleteRenderbuffers(1, &_drawRenderbuffer);
_drawRenderbuffer = 0;
#endif #endif
for (auto package : messages) { }
TexturePointer texturePointer = package.texture.lock();
// Texture no longer exists, move on to the next bool GLTextureTransferHelper::process() {
if (!texturePointer) { #ifdef THREADED_TEXTURE_TRANSFER
// Take any new textures off the queue
TextureList newTransferTextures;
{
Lock lock(_mutex);
newTransferTextures.swap(_pendingTextures);
}
if (!newTransferTextures.empty()) {
for (auto& texturePointer : newTransferTextures) {
#ifdef HAVE_NSIGHT
_map[texturePointer] = nvtxRangeStart("TextureTansfer");
#endif
GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer);
object->startTransfer();
_transferringTextures.push_back(texturePointer);
_textureIterator = _transferringTextures.begin();
}
}
// No transfers in progress, sleep
if (_transferringTextures.empty()) {
QThread::usleep(1);
return true;
}
static auto lastReport = usecTimestampNow();
auto now = usecTimestampNow();
auto lastReportInterval = now - lastReport;
if (lastReportInterval > USECS_PER_SECOND * 4) {
lastReport = now;
qDebug() << "Texture list " << _transferringTextures.size();
}
for (auto _textureIterator = _transferringTextures.begin(); _textureIterator != _transferringTextures.end();) {
auto texture = *_textureIterator;
GLTexture* gltexture = Backend::getGPUObject<GLTexture>(*texture);
if (gltexture->continueTransfer()) {
++_textureIterator;
continue; continue;
} }
if (package.fence) { gltexture->finishTransfer();
auto result = glClientWaitSync(package.fence, 0, 0); glNamedFramebufferTexture(_readFramebuffer, GL_COLOR_ATTACHMENT0, gltexture->_id, 0);
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) { glBlitNamedFramebuffer(_readFramebuffer, _drawFramebuffer, 0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// Minimum sleep clientWait();
QThread::usleep(1); gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp();
result = glClientWaitSync(package.fence, 0, 0); gltexture->updateSize();
} gltexture->setSyncState(gpu::gl::GLSyncState::Transferred);
assert(GL_CONDITION_SATISFIED == result || GL_ALREADY_SIGNALED == result); Backend::decrementTextureGPUTransferCount();
glDeleteSync(package.fence); #ifdef HAVE_NSIGHT
package.fence = 0; // Mark the texture as transferred
} nvtxRangeEnd(_map[texture]);
_map.erase(texture);
GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer); #endif
_textureIterator = _transferringTextures.erase(_textureIterator);
do_transfer(*object);
glBindTexture(object->_target, 0);
{
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
assert(fence);
auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
// Minimum sleep
QThread::usleep(1);
result = glClientWaitSync(fence, 0, 0);
}
glDeleteSync(fence);
}
object->_contentStamp = texturePointer->getDataStamp();
object->setSyncState(GLSyncState::Transferred);
} }
#ifdef THREADED_TEXTURE_TRANSFER
_context.doneCurrent(); if (!_transferringTextures.empty()) {
// Don't saturate the GPU
clientWait();
} else {
// Don't saturate the CPU
QThread::msleep(1);
}
#else
QThread::msleep(1);
#endif #endif
return true; return true;
} }

View file

@ -23,27 +23,38 @@
namespace gpu { namespace gl { namespace gpu { namespace gl {
struct TextureTransferPackage { using TextureList = std::list<TexturePointer>;
std::weak_ptr<Texture> texture; using TextureListIterator = TextureList::iterator;
GLsync fence;
};
class GLTextureTransferHelper : public GenericQueueThread<TextureTransferPackage> { class GLTextureTransferHelper : public GenericThread {
public: public:
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 postTransfer(const gpu::TexturePointer& texturePointer);
protected: protected:
void setup() override; void setup() override;
void shutdown() override; void shutdown() override;
bool processQueueItems(const Queue& messages) override; bool process() override;
void do_transfer(GLTexture& texturePointer);
private: private:
#ifdef THREADED_TEXTURE_TRANSFER
::gl::OffscreenContext _context; ::gl::OffscreenContext _context;
// A mutex for protecting items access on the render and transfer threads
Mutex _mutex;
// Textures that have been submitted for transfer
TextureList _pendingTextures;
// Textures currently in the transfer process
// Only used on the transfer thread
TextureList _transferringTextures;
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

@ -46,10 +46,10 @@ public:
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, GL41Texture* original); GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, GL41Texture* original);
protected: protected:
void transferMip(uint16_t mipLevel, uint8_t face = 0) const; void transferMip(uint16_t mipLevel, uint8_t face) const;
void startTransfer() override;
void allocateStorage() const override; void allocateStorage() const override;
void updateSize() const override; void updateSize() const override;
void transfer() 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; void withPreservedTexture(std::function<void()> f) const override;

View file

@ -42,7 +42,7 @@ GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture&
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GL41Texture* original) : GLTexture(backend, texture, allocate(), original) {} GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GL41Texture* original) : GLTexture(backend, texture, allocate(), original) {}
void GL41Backend::GL41Texture::withPreservedTexture(std::function<void()> f) const { void GL41Texture::withPreservedTexture(std::function<void()> f) const {
GLint boundTex = -1; GLint boundTex = -1;
switch (_target) { switch (_target) {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
@ -64,14 +64,14 @@ void GL41Backend::GL41Texture::withPreservedTexture(std::function<void()> f) con
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
void GL41Backend::GL41Texture::generateMips() const { void GL41Texture::generateMips() const {
withPreservedTexture([&] { withPreservedTexture([&] {
glGenerateMipmap(_target); glGenerateMipmap(_target);
}); });
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
void GL41Backend::GL41Texture::allocateStorage() const { void GL41Texture::allocateStorage() const {
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
@ -94,7 +94,7 @@ void GL41Backend::GL41Texture::allocateStorage() const {
} }
} }
void GL41Backend::GL41Texture::updateSize() const { void GL41Texture::updateSize() const {
setSize(_virtualSize); setSize(_virtualSize);
if (!_id) { if (!_id) {
return; return;
@ -130,7 +130,7 @@ void GL41Backend::GL41Texture::updateSize() const {
} }
// Move content bits from the CPU to the GPU for a given mip / face // Move content bits from the CPU to the GPU for a given mip / face
void GL41Backend::GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) const { void GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) const {
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
//GLenum target = getFaceTargets()[face]; //GLenum target = getFaceTargets()[face];
@ -140,15 +140,9 @@ void GL41Backend::GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) cons
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
// This should never happen on the main thread void GL41Texture::startTransfer() {
// Move content bits from the CPU to the GPU
void GL41Backend::GL41Texture::transfer() const {
PROFILE_RANGE(__FUNCTION__); PROFILE_RANGE(__FUNCTION__);
//qDebug() << "Transferring texture: " << _privateTexture; Parent::startTransfer();
// Need to update the content of the GPU object from the source sysmem of the texture
if (_contentStamp >= _gpuObject.getDataStamp()) {
return;
}
glBindTexture(_target, _id); glBindTexture(_target, _id);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
@ -175,38 +169,16 @@ void GL41Backend::GL41Texture::transfer() const {
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo); glDeleteFramebuffers(1, &fbo);
} else { } else {
// GO through the process of allocating the correct storage and/or update the content // transfer pixels from each faces
switch (_gpuObject.getType()) { uint8_t numFaces = (Texture::TEX_CUBE == _gpuObject.getType()) ? CUBE_NUM_FACES : 1;
case Texture::TEX_2D: for (uint8_t f = 0; f < numFaces; f++) {
{ for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
for (uint16_t i = _minMip; i <= _maxMip; ++i) { if (_gpuObject.isStoredMipFaceAvailable(i, f)) {
if (_gpuObject.isStoredMipFaceAvailable(i)) { transferMip(i, f);
transferMip(i);
}
} }
} }
break;
case Texture::TEX_CUBE:
// transfer pixels from each faces
for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) {
for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
if (_gpuObject.isStoredMipFaceAvailable(i, f)) {
transferMip(i, f);
}
}
}
break;
default:
qCWarning(gpugl41logging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported";
break;
} }
} }
if (_gpuObject.isAutogenerateMips()) {
glGenerateMipmap(_target);
(void)CHECK_GL_ERROR();
}
} }
void GL41Backend::GL41Texture::syncSampler() const { void GL41Backend::GL41Texture::syncSampler() const {

View file

@ -18,6 +18,29 @@ 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
@ -29,19 +52,25 @@ public:
class GL45Texture : public GLTexture { class GL45Texture : public GLTexture {
using Parent = GLTexture; using Parent = GLTexture;
GLuint allocate(const Texture& texture); static GLuint allocate(const Texture& texture);
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(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original);
~GL45Texture();
protected: protected:
void startTransfer() override;
bool continueTransfer() override;
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 allocateStorage() const override; void allocateStorage() const override;
void updateSize() const override; void updateSize() const override;
void transfer() 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; void withPreservedTexture(std::function<void()> f) const override;
TransferState _transferState;
}; };

View file

@ -10,8 +10,11 @@
// //
#include "GL45Backend.h" #include "GL45Backend.h"
#include <mutex>
#include <condition_variable>
#include <unordered_set> #include <unordered_set>
#include <unordered_map> #include <unordered_map>
#include <glm/gtx/component_wise.hpp>
#include <QtCore/QThread> #include <QtCore/QThread>
@ -21,10 +24,111 @@ using namespace gpu;
using namespace gpu::gl; using namespace gpu::gl;
using namespace gpu::gl45; using namespace gpu::gl45;
#define SPARSE_TEXTURES 1
// Allocate 1 MB of buffer space for paged transfers
#define DEFAULT_PAGE_BUFFER_SIZE (1024*1024)
using GL45Texture = GL45Backend::GL45Texture; using GL45Texture = GL45Backend::GL45Texture;
GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
return GL45Texture::sync<GL45Texture>(*this, texture, transfer);
}
TransferState::TransferState(GLTexture& texture) : _texture(texture) {
}
void TransferState::updateSparse() {
glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel);
_internalFormat = gl::GLTexelFormat::evalGLTexelFormat(_texture._gpuObject.getTexelFormat(), _texture._gpuObject.getTexelFormat()).internalFormat;
ivec3 pageSize;
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;
}
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() {
if ((_mipOffset.x + _pageSize.x) < _mipDimensions.x) {
_mipOffset.x += _pageSize.x;
return true;
}
if ((_mipOffset.y + _pageSize.y) < _mipDimensions.y) {
_mipOffset.x = 0;
_mipOffset.y += _pageSize.y;
return true;
}
if (_mipOffset.z + _pageSize.z < _mipDimensions.z) {
_mipOffset.x = 0;
_mipOffset.y = 0;
++_mipOffset.z;
return true;
}
// Done with this mip?, move on to the next mip
if (_mipLevel + 1 < _texture.usedMipLevels()) {
_mipOffset = uvec3(0);
++_mipLevel;
updateMip();
return true;
}
uint8_t maxFace = (uint8_t)((_texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1);
uint8_t nextFace = _face + 1;
// Done with this face? Move on to the next
if (nextFace < maxFace) {
++_face;
_mipOffset = uvec3(0);
_mipLevel = 0;
updateMip();
return true;
}
return false;
}
#define DEFAULT_GL_PIXEL_ALIGNMENT 4
void TransferState::populatePage(std::vector<uint8_t>& buffer) {
uvec3 pageSize = currentPageSize();
auto bytesPerPageLine = _bytesPerPixel * pageSize.x;
if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) {
bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT);
assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT));
}
auto totalPageSize = bytesPerPageLine * pageSize.y;
if (totalPageSize > buffer.size()) {
buffer.resize(totalPageSize);
}
uint8_t* dst = &buffer[0];
for (uint32_t y = 0; y < pageSize.y; ++y) {
uint32_t srcOffset = (_bytesPerLine * (_mipOffset.y + y)) + (_bytesPerPixel * _mipOffset.x);
uint32_t dstOffset = bytesPerPageLine * y;
memcpy(dst + dstOffset, _srcPointer + srcOffset, pageSize.x * _bytesPerPixel);
}
}
uvec3 TransferState::currentPageSize() const {
return glm::clamp(_mipDimensions - _mipOffset, uvec3(1), _pageSize);
}
GLuint GL45Texture::allocate(const Texture& texture) { GLuint GL45Texture::allocate(const Texture& texture) {
Backend::incrementTextureGPUCount();
GLuint result; GLuint result;
glCreateTextures(getGLTextureType(texture), 1, &result); glCreateTextures(getGLTextureType(texture), 1, &result);
return result; return result;
@ -34,26 +138,38 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) {
return GL45Texture::getId<GL45Texture>(*this, texture, transfer); return GL45Texture::getId<GL45Texture>(*this, texture, transfer);
} }
GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
return GL45Texture::sync<GL45Texture>(*this, texture, transfer); : GLTexture(backend, texture, allocate(texture), transferrable), _transferState(*this) {
#if SPARSE_TEXTURES
if (transferrable) {
glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE);
}
#endif
} }
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable) GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original)
: GLTexture(backend, texture, allocate(texture), transferrable) {} : GLTexture(backend, texture, allocate(texture), original), _transferState(*this) { }
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original) GL45Texture::~GL45Texture() {
: GLTexture(backend, texture, allocate(texture), original) {} // FIXME do we need to explicitly deallocate the virtual memory here?
//if (_transferrable) {
// for (uint16_t mipLevel = 0; mipLevel < usedMipLevels(); ++i) {
// glTexturePageCommitmentEXT(_id, mipLevel, offset.x, offset.y, offset.z, size.x, size.y, size.z, GL_TRUE);
// }
//}
}
void GL45Backend::GL45Texture::withPreservedTexture(std::function<void()> f) const { void GL45Texture::withPreservedTexture(std::function<void()> f) const {
f(); f();
} }
void GL45Backend::GL45Texture::generateMips() const { void GL45Texture::generateMips() const {
glGenerateTextureMipmap(_id); glGenerateTextureMipmap(_id);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
void GL45Backend::GL45Texture::allocateStorage() const { void GL45Texture::allocateStorage() const {
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
@ -66,7 +182,7 @@ void GL45Backend::GL45Texture::allocateStorage() const {
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
void GL45Backend::GL45Texture::updateSize() const { void GL45Texture::updateSize() const {
setSize(_virtualSize); setSize(_virtualSize);
if (!_id) { if (!_id) {
return; return;
@ -77,86 +193,50 @@ void GL45Backend::GL45Texture::updateSize() const {
} }
} }
// Move content bits from the CPU to the GPU for a given mip / face void GL45Texture::startTransfer() {
void GL45Backend::GL45Texture::transferMip(uint16_t mipLevel, uint8_t face) const { Parent::startTransfer();
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); _transferState.updateSparse();
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); _transferState.updateMip();
auto size = _gpuObject.evalMipDimensions(mipLevel);
if (GL_TEXTURE_2D == _target) {
glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
} else if (GL_TEXTURE_CUBE_MAP == _target) {
// 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());
auto target = CUBE_FACE_LAYOUT[face];
glTextureSubImage2DEXT(_id, target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
} else {
Q_ASSERT(false);
}
(void)CHECK_GL_ERROR();
} }
// This should never happen on the main thread bool GL45Texture::continueTransfer() {
// Move content bits from the CPU to the GPU static std::vector<uint8_t> buffer;
void GL45Backend::GL45Texture::transfer() const { if (buffer.empty()) {
PROFILE_RANGE(__FUNCTION__); buffer.resize(DEFAULT_PAGE_BUFFER_SIZE);
//qDebug() << "Transferring texture: " << _privateTexture;
// Need to update the content of the GPU object from the source sysmem of the texture
if (_contentStamp >= _gpuObject.getDataStamp()) {
return;
} }
uvec3 pageSize = _transferState.currentPageSize();
uvec3 offset = _transferState._mipOffset;
if (_downsampleSource._texture) { #if SPARSE_TEXTURES
GLuint fbo { 0 }; if (_transferState._mipLevel <= _transferState._maxSparseLevel) {
glCreateFramebuffers(1, &fbo); glTexturePageCommitmentEXT(_id, _transferState._mipLevel,
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); offset.x, offset.y, _transferState._face,
// Find the distance between the old min mip and the new one pageSize.x, pageSize.y, pageSize.z,
uint16 mipOffset = _minMip - _downsampleSource._minMip; GL_TRUE);
for (uint16 i = _minMip; i <= _maxMip; ++i) { }
uint16 targetMip = i - _minMip; #endif
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();
glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, dimensions.x, dimensions.y);
(void)CHECK_GL_ERROR();
}
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
} else {
// GO through the process of allocating the correct storage and/or update the content
switch (_gpuObject.getType()) {
case Texture::TEX_2D:
{
for (uint16_t i = _minMip; i <= _maxMip; ++i) {
if (_gpuObject.isStoredMipFaceAvailable(i)) {
transferMip(i);
}
}
}
break;
case Texture::TEX_CUBE: if (_transferState._srcPointer) {
// transfer pixels from each faces // Transfer the mip data
for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) { _transferState.populatePage(buffer);
for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { if (GL_TEXTURE_2D == _target) {
if (_gpuObject.isStoredMipFaceAvailable(i, f)) { glTextureSubImage2D(_id, _transferState._mipLevel,
transferMip(i, f); offset.x, offset.y,
} pageSize.x, pageSize.y,
} _transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]);
} } else if (GL_TEXTURE_CUBE_MAP == _target) {
break; auto target = CUBE_FACE_LAYOUT[_transferState._face];
// DSA ARB does not work on AMD, so use EXT
default: // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData());
qCWarning(gpugl45logging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported"; glTextureSubImage2DEXT(_id, target, _transferState._mipLevel,
break; offset.x, offset.y,
pageSize.x, pageSize.y,
_transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]);
} }
} }
if (_gpuObject.isAutogenerateMips()) {
glGenerateTextureMipmap(_id); serverWait();
(void)CHECK_GL_ERROR(); return _transferState.increment();
}
} }
void GL45Backend::GL45Texture::syncSampler() const { void GL45Backend::GL45Texture::syncSampler() const {

View file

@ -18,12 +18,15 @@
#include <QRunnable> #include <QRunnable>
#include <QThreadPool> #include <QThreadPool>
#include <QImageReader> #include <QImageReader>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/random.hpp> #include <glm/gtc/random.hpp>
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <NumericalConstants.h>
#include <shared/NsightHelpers.h> #include <shared/NsightHelpers.h>
#include <Finally.h> #include <Finally.h>
@ -307,6 +310,24 @@ ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QByteArra
_url(url), _url(url),
_content(data) _content(data)
{ {
#if DEBUG_DUMP_TEXTURE_LOADS
static auto start = usecTimestampNow() / USECS_PER_MSEC;
auto now = usecTimestampNow() / USECS_PER_MSEC - start;
QString urlStr = _url.toString();
auto dot = urlStr.lastIndexOf(".");
QString outFileName = QString(QCryptographicHash::hash(urlStr.toLocal8Bit(), QCryptographicHash::Md5).toHex()) + urlStr.right(urlStr.length() - dot);
QFile loadRecord("h:/textures/loads.txt");
loadRecord.open(QFile::Text | QFile::Append | QFile::ReadWrite);
loadRecord.write(QString("%1 %2\n").arg(now).arg(outFileName).toLocal8Bit());
outFileName = "h:/textures/" + outFileName;
QFileInfo outInfo(outFileName);
if (!outInfo.exists()) {
QFile outFile(outFileName);
outFile.open(QFile::WriteOnly | QFile::Truncate);
outFile.write(data);
outFile.close();
}
#endif
} }
void ImageReader::listSupportedImageFormats() { void ImageReader::listSupportedImageFormats() {

View file

@ -22,6 +22,13 @@ using namespace gpu;
// FIXME: Declare this to enable compression // FIXME: Declare this to enable compression
//#define COMPRESS_TEXTURES //#define COMPRESS_TEXTURES
bool DEV_DECIMATE_TEXTURES = false;
QImage processSourceImage(const QImage& srcImage) {
if (DEV_DECIMATE_TEXTURES) {
return srcImage.scaled(srcImage.size() * 0.5f);
}
return srcImage;
}
void TextureMap::setTextureSource(TextureSourcePointer& textureSource) { void TextureMap::setTextureSource(TextureSourcePointer& textureSource) {
_textureSource = textureSource; _textureSource = textureSource;
@ -53,7 +60,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
} }
const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) { const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
QImage image = srcImage; QImage image = processSourceImage(srcImage);
validAlpha = false; validAlpha = false;
alphaAsMask = true; alphaAsMask = true;
const uint8 OPAQUE_ALPHA = 255; const uint8 OPAQUE_ALPHA = 255;
@ -221,7 +228,7 @@ gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImag
gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = srcImage; QImage image = processSourceImage(srcImage);
if (image.format() != QImage::Format_RGB888) { if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888); image = image.convertToFormat(QImage::Format_RGB888);
@ -254,8 +261,8 @@ double mapComponent(double sobelValue) {
} }
gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = srcImage; QImage image = processSourceImage(srcImage);
if (image.format() != QImage::Format_RGB888) { if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888); image = image.convertToFormat(QImage::Format_RGB888);
} }
@ -325,7 +332,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
} }
gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = srcImage; QImage image = processSourceImage(srcImage);
if (!image.hasAlphaChannel()) { if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) { if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888); image = image.convertToFormat(QImage::Format_RGB888);
@ -358,7 +365,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
} }
gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = srcImage; QImage image = processSourceImage(srcImage);
if (!image.hasAlphaChannel()) { if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) { if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888); image = image.convertToFormat(QImage::Format_RGB888);
@ -395,7 +402,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
} }
gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = srcImage; QImage image = processSourceImage(srcImage);
if (!image.hasAlphaChannel()) { if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) { if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888); image = image.convertToFormat(QImage::Format_RGB888);
@ -687,7 +694,7 @@ const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS)
gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) { gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) {
gpu::Texture* theTexture = nullptr; gpu::Texture* theTexture = nullptr;
if ((srcImage.width() > 0) && (srcImage.height() > 0)) { if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
QImage image = srcImage; QImage image = processSourceImage(srcImage);
if (image.format() != QImage::Format_RGB888) { if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888); image = image.convertToFormat(QImage::Format_RGB888);
} }

View file

@ -46,7 +46,7 @@ inline btTransform glmToBullet(const glm::mat4& m) {
} }
inline glm::mat4 bulletToGLM(const btTransform& t) { inline glm::mat4 bulletToGLM(const btTransform& t) {
glm::mat4 m(glm::mat4::_null); glm::mat4 m;
const btMatrix3x3& basis = t.getBasis(); const btMatrix3x3& basis = t.getBasis();
// copy over 3x3 part // copy over 3x3 part

View file

@ -8,4 +8,4 @@ if (WIN32)
endif() endif()
target_zlib() target_zlib()
target_nsight() target_nsight()

View file

@ -9,8 +9,6 @@
// 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 <glm/gtx/extented_min_max.hpp>
#include "AABox.h" #include "AABox.h"
#include "AACube.h" #include "AACube.h"
#include "Extents.h" #include "Extents.h"
@ -25,7 +23,7 @@ AACube::AACube(const Extents& other) :
_corner(other.minimum) _corner(other.minimum)
{ {
glm::vec3 dimensions = other.maximum - other.minimum; glm::vec3 dimensions = other.maximum - other.minimum;
_scale = glm::max(dimensions.x, dimensions.y, dimensions.z); _scale = glm::compMax(dimensions);
} }
AACube::AACube(const glm::vec3& corner, float size) : AACube::AACube(const glm::vec3& corner, float size) :
@ -479,8 +477,8 @@ AACube& AACube::operator += (const glm::vec3& point) {
glm::vec3 scaleOld = oldMaximumPoint - _corner; glm::vec3 scaleOld = oldMaximumPoint - _corner;
glm::vec3 scalePoint = point - _corner; glm::vec3 scalePoint = point - _corner;
_scale = glm::max(_scale, scalePoint.x, scalePoint.y, scalePoint.z); _scale = std::max(_scale, glm::compMax(scalePoint));
_scale = glm::max(_scale, scaleOld.x, scaleOld.y, scaleOld.z); _scale = std::max(_scale, glm::compMax(scaleOld));
return (*this); return (*this);
} }

View file

@ -14,7 +14,7 @@
#define hifi_Extents_h #define hifi_Extents_h
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtx/extented_min_max.hpp> #include <glm/gtx/component_wise.hpp>
#include <QDebug> #include <QDebug>
#include "StreamUtils.h" #include "StreamUtils.h"
@ -67,7 +67,7 @@ public:
void transform(const Transform& transform); void transform(const Transform& transform);
glm::vec3 size() const { return maximum - minimum; } glm::vec3 size() const { return maximum - minimum; }
float largestDimension() const {glm::vec3 s = size(); return glm::max(s[0], s[1], s[2]); } float largestDimension() const { return glm::compMax(size()); }
/// \return new Extents which is original rotated around orign by rotation /// \return new Extents which is original rotated around orign by rotation
Extents getRotated(const glm::quat& rotation) const { Extents getRotated(const glm::quat& rotation) const {

View file

@ -203,19 +203,19 @@ inline float lerp(float x, float y, float a) {
// vec2 lerp - linear interpolate // vec2 lerp - linear interpolate
template<typename T, glm::precision P> template<typename T, glm::precision P>
glm::detail::tvec2<T, P> lerp(const glm::detail::tvec2<T, P>& x, const glm::detail::tvec2<T, P>& y, T a) { glm::tvec2<T, P> lerp(const glm::tvec2<T, P>& x, const glm::tvec2<T, P>& y, T a) {
return x * (T(1) - a) + (y * a); return x * (T(1) - a) + (y * a);
} }
// vec3 lerp - linear interpolate // vec3 lerp - linear interpolate
template<typename T, glm::precision P> template<typename T, glm::precision P>
glm::detail::tvec3<T, P> lerp(const glm::detail::tvec3<T, P>& x, const glm::detail::tvec3<T, P>& y, T a) { glm::tvec3<T, P> lerp(const glm::tvec3<T, P>& x, const glm::tvec3<T, P>& y, T a) {
return x * (T(1) - a) + (y * a); return x * (T(1) - a) + (y * a);
} }
// vec4 lerp - linear interpolate // vec4 lerp - linear interpolate
template<typename T, glm::precision P> template<typename T, glm::precision P>
glm::detail::tvec4<T, P> lerp(const glm::detail::tvec4<T, P>& x, const glm::detail::tvec4<T, P>& y, T a) { glm::tvec4<T, P> lerp(const glm::tvec4<T, P>& x, const glm::tvec4<T, P>& y, T a) {
return x * (T(1) - a) + (y * a); return x * (T(1) - a) + (y * a);
} }

View file

@ -797,7 +797,7 @@ void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) {
} }
glm::vec3 SpatiallyNestable::getLocalVelocity() const { glm::vec3 SpatiallyNestable::getLocalVelocity() const {
glm::vec3 result(glm::vec3::_null); glm::vec3 result;
_velocityLock.withReadLock([&] { _velocityLock.withReadLock([&] {
result = _velocity; result = _velocity;
}); });
@ -811,7 +811,7 @@ void SpatiallyNestable::setLocalVelocity(const glm::vec3& velocity) {
} }
glm::vec3 SpatiallyNestable::getLocalAngularVelocity() const { glm::vec3 SpatiallyNestable::getLocalAngularVelocity() const {
glm::vec3 result(glm::vec3::_null); glm::vec3 result;
_angularVelocityLock.withReadLock([&] { _angularVelocityLock.withReadLock([&] {
result = _angularVelocity; result = _angularVelocity;
}); });

View file

@ -14,6 +14,9 @@ link_hifi_libraries(shared octree gl gpu gpu-gl render model model-networking ne
package_libraries_for_deployment() package_libraries_for_deployment()
target_gli()
target_glm()
target_zlib() target_zlib()
add_dependency_external_projects(quazip) add_dependency_external_projects(quazip)
find_package(QuaZip REQUIRED) find_package(QuaZip REQUIRED)

View file

@ -0,0 +1,70 @@
//
// Created by Bradley Austin Davis on 2016/09/03
// 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 "GLIHelpers.h"
#include <QtCore/QFileInfo>
#include <QtGui/QImage>
#include <gli/texture2d.hpp>
#include <gli/convert.hpp>
#include <gli/generate_mipmaps.hpp>
#include <gpu/Texture.h>
gli::format fromQImageFormat(QImage::Format format) {
switch (format) {
case QImage::Format_RGB32:
return gli::format::FORMAT_BGRA8_UNORM_PACK8;
case QImage::Format_ARGB32:
return gli::format::FORMAT_BGRA8_UNORM_PACK8;
case QImage::Format_Grayscale8:
return gli::format::FORMAT_L8_UNORM_PACK8;
default:
return gli::format::FORMAT_UNDEFINED;
}
}
QString getKtxFileName(const QString& sourceFileName) {
QFileInfo fileInfo(sourceFileName);
QString name = fileInfo.completeBaseName();
QString ext = fileInfo.suffix();
QString path = fileInfo.absolutePath();
return path + "/" + name + ".ktx";
}
QString convertTexture(const QString& sourceFile) {
if (sourceFile.endsWith(".ktx") || sourceFile.endsWith(".dds")) {
return sourceFile;
}
QImage sourceImage(sourceFile);
gli::texture2d workTexture(
fromQImageFormat(sourceImage.format()),
gli::extent2d(sourceImage.width(), sourceImage.height()));
auto sourceSize = sourceImage.byteCount();
assert(sourceSize == workTexture[workTexture.base_level()].size());
memcpy(workTexture[workTexture.base_level()].data(), sourceImage.constBits(), sourceSize);
QString resultFile = getKtxFileName(sourceFile) ;
gli::texture2d TextureMipmaped = gli::generate_mipmaps(workTexture, gli::FILTER_LINEAR);
gli::save(TextureMipmaped, resultFile.toLocal8Bit().data());
gli::texture loaded = gli::load(resultFile.toLocal8Bit().data());
return sourceFile;
}
gpu::TexturePointer processTexture(const QString& sourceFile) {
auto ktxFile = convertTexture(sourceFile);
gli::texture texture = gli::load(ktxFile.toLocal8Bit().data());
if (texture.empty()) {
return gpu::TexturePointer();
}
// FIXME load the actual KTX texture
return gpu::TexturePointer();
}

View file

@ -0,0 +1,47 @@
//
// Created by Bradley Austin Davis on 2016/09/03
// 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 _GLIHelpers_H_
#define _GLIHelpers_H_
#include <qglobal.h>
#include <QtCore/QString>
// Work around for a bug in the MSVC compiler that chokes when you use GLI and Qt headers together.
#define gli glm
#ifdef Q_OS_MAC
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wignored-qualifiers"
#endif
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wempty-body"
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-result"
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
#include <gli/gli.hpp>
#ifdef Q_OS_MAC
#pragma clang diagnostic pop
#endif
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
#include <gpu/Forward.h>
gpu::TexturePointer processTexture(const QString& file);
#endif

View file

@ -11,9 +11,6 @@
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <gl/Config.h>
#include <gl/Context.h>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QElapsedTimer> #include <QtCore/QElapsedTimer>
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
@ -41,6 +38,7 @@
#include <quazip5/JlCompress.h> #include <quazip5/JlCompress.h>
#include "GLIHelpers.h"
#include <shared/RateCounter.h> #include <shared/RateCounter.h>
#include <AssetClient.h> #include <AssetClient.h>
#include <PathUtils.h> #include <PathUtils.h>
@ -55,15 +53,15 @@
#include <TextureCache.h> #include <TextureCache.h>
#include <FramebufferCache.h> #include <FramebufferCache.h>
#include <GeometryCache.h> #include <GeometryCache.h>
#include <DeferredLightingEffect.h>
#include <RenderShadowTask.h> #include <gl/Config.h>
#include <RenderDeferredTask.h> #include <gl/Context.h>
extern QThread* RENDER_THREAD; extern QThread* RENDER_THREAD;
static const QString DATA_SET = "https://hifi-content.s3.amazonaws.com/austin/textures.zip"; static const QString DATA_SET = "https://hifi-content.s3.amazonaws.com/austin/textures.zip";
static const QTemporaryDir DATA_DIR; static QDir DATA_DIR = QDir(QString("h:/textures"));
static QTemporaryDir* DOWNLOAD_DIR = nullptr;
class FileDownloader : public QObject { class FileDownloader : public QObject {
Q_OBJECT Q_OBJECT
@ -81,7 +79,7 @@ public:
} }
} }
private slots: private slots:
void fileDownloaded(QNetworkReply* pReply) { void fileDownloaded(QNetworkReply* pReply) {
_handler(pReply->readAll()); _handler(pReply->readAll());
pReply->deleteLater(); pReply->deleteLater();
@ -132,8 +130,6 @@ public:
_gpuContext = std::make_shared<gpu::Context>(); _gpuContext = std::make_shared<gpu::Context>();
_backend = _gpuContext->getBackend(); _backend = _gpuContext->getBackend();
_context.makeCurrent(); _context.makeCurrent();
DependencyManager::get<DeferredLightingEffect>()->init();
_context.makeCurrent();
initContext.create(); initContext.create();
_context.doneCurrent(); _context.doneCurrent();
std::unique_lock<std::mutex> lock(_mutex); std::unique_lock<std::mutex> lock(_mutex);
@ -191,7 +187,7 @@ public:
_gpuContext->executeFrame(frame); _gpuContext->executeFrame(frame);
{ {
auto geometryCache = DependencyManager::get<GeometryCache>(); auto geometryCache = DependencyManager::get<GeometryCache>();
gpu::Batch presentBatch; gpu::Batch presentBatch;
presentBatch.setViewportTransform({ 0, 0, _size.width(), _size.height() }); presentBatch.setViewportTransform({ 0, 0, _size.width(), _size.height() });
@ -277,16 +273,6 @@ public:
} }
}; };
QString fileForPath(const QString& name) {
QCryptographicHash hash(QCryptographicHash::Md5);
hash.addData(name.toLocal8Bit().data(), name.length());
QString hashStr = QString(hash.result().toHex());
auto dot = name.lastIndexOf('.');
QString extension = name.right(name.length() - dot);
QString result = DATA_DIR.path() + "/" + hashStr + extension;
return result;
}
// Create a simple OpenGL window that renders text in various ways // Create a simple OpenGL window that renders text in various ways
class QTestWindow : public QWindow { class QTestWindow : public QWindow {
public: public:
@ -296,7 +282,6 @@ public:
//DependencyManager::registerInheritance<SpatialParentFinder, ParentFinder>(); //DependencyManager::registerInheritance<SpatialParentFinder, ParentFinder>();
DependencyManager::set<AddressManager>(); DependencyManager::set<AddressManager>();
DependencyManager::set<NodeList>(NodeType::Agent); DependencyManager::set<NodeList>(NodeType::Agent);
DependencyManager::set<DeferredLightingEffect>();
DependencyManager::set<ResourceCacheSharedItems>(); DependencyManager::set<ResourceCacheSharedItems>();
DependencyManager::set<TextureCache>(); DependencyManager::set<TextureCache>();
DependencyManager::set<FramebufferCache>(); DependencyManager::set<FramebufferCache>();
@ -316,7 +301,7 @@ public:
_currentTexture = _textures.end(); _currentTexture = _textures.end();
{ {
QStringList stringList; QStringList stringList;
QFile textFile("h:/textures/loads.txt"); QFile textFile(DATA_DIR.path() + "/loads.txt");
textFile.open(QFile::ReadOnly); textFile.open(QFile::ReadOnly);
//... (open the file for reading, etc.) //... (open the file for reading, etc.)
QTextStream textStream(&textFile); QTextStream textStream(&textFile);
@ -332,8 +317,7 @@ public:
auto index = s.indexOf(" "); auto index = s.indexOf(" ");
QString timeStr = s.left(index); QString timeStr = s.left(index);
auto time = timeStr.toUInt(); auto time = timeStr.toUInt();
QString path = s.right(s.length() - index).trimmed(); QString path = DATA_DIR.path() + "/" + s.right(s.length() - index).trimmed();
path = fileForPath(path);
qDebug() << "Path " << path; qDebug() << "Path " << path;
if (!QFileInfo(path).exists()) { if (!QFileInfo(path).exists()) {
continue; continue;
@ -341,7 +325,7 @@ public:
_textureLoads.push({ time, path, s }); _textureLoads.push({ time, path, s });
} }
} }
installEventFilter(this); installEventFilter(this);
QThreadPool::globalInstance()->setMaxThreadCount(2); QThreadPool::globalInstance()->setMaxThreadCount(2);
QThread::currentThread()->setPriority(QThread::HighestPriority); QThread::currentThread()->setPriority(QThread::HighestPriority);
@ -436,7 +420,7 @@ private:
QSize windowSize = _size; QSize windowSize = _size;
auto framebufferCache = DependencyManager::get<FramebufferCache>(); auto framebufferCache = DependencyManager::get<FramebufferCache>();
framebufferCache->setFrameBufferSize(windowSize); framebufferCache->setFrameBufferSize(windowSize);
// Final framebuffer that will be handled to the display-plugin // Final framebuffer that will be handled to the display-plugin
render(); render();
@ -462,8 +446,9 @@ private:
qDebug() << "Missing file " << front.file; qDebug() << "Missing file " << front.file;
} else { } else {
qDebug() << "Loading " << front.src; qDebug() << "Loading " << front.src;
auto file = front.file.toLocal8Bit().toStdString();
processTexture(file.c_str());
_textures.push_back(DependencyManager::get<TextureCache>()->getImageTexture(front.file)); _textures.push_back(DependencyManager::get<TextureCache>()->getImageTexture(front.file));
_currentTexture = _textures.begin();
} }
_textureLoads.pop(); _textureLoads.pop();
if (_textureLoads.empty()) { if (_textureLoads.empty()) {
@ -481,7 +466,7 @@ private:
}); });
PROFILE_RANGE(__FUNCTION__); PROFILE_RANGE(__FUNCTION__);
auto framebuffer = DependencyManager::get<FramebufferCache>()->getFramebuffer(); auto framebuffer = DependencyManager::get<FramebufferCache>()->getFramebuffer();
gpu::doInBatch(gpuContext, [&](gpu::Batch& batch) { gpu::doInBatch(gpuContext, [&](gpu::Batch& batch) {
batch.enableStereo(false); batch.enableStereo(false);
batch.setFramebuffer(framebuffer); batch.setFramebuffer(framebuffer);
@ -494,8 +479,7 @@ private:
} }
if (_currentTexture == _textures.end()) { if (_currentTexture == _textures.end()) {
_currentTexture = _textures.begin(); _currentTexture = _textures.begin();
} }
if (_currentTexture != _textures.end()) { if (_currentTexture != _textures.end()) {
batch.setResourceTexture(0, *_currentTexture); batch.setResourceTexture(0, *_currentTexture);
} }
@ -505,7 +489,7 @@ private:
auto frame = gpuContext->endFrame(); auto frame = gpuContext->endFrame();
frame->framebuffer = framebuffer; frame->framebuffer = framebuffer;
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer){ frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer); DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer);
}; };
_renderThread.submitFrame(frame); _renderThread.submitFrame(frame);
@ -546,20 +530,23 @@ hifi.gpu=true
)V0G0N"; )V0G0N";
void unzipTestData(const QByteArray& zipData) { void unzipTestData(const QByteArray& zipData) {
DOWNLOAD_DIR = new QTemporaryDir();
QTemporaryDir& tempDir = *DOWNLOAD_DIR;
QTemporaryFile zipFile; QTemporaryFile zipFile;
if (zipFile.open()) { if (zipFile.open()) {
zipFile.write(zipData); zipFile.write(zipData);
zipFile.close(); zipFile.close();
} }
qDebug() << zipFile.fileName(); qDebug() << zipFile.fileName();
if (!DATA_DIR.isValid()) { if (!tempDir.isValid()) {
qFatal("Unable to create temp dir"); qFatal("Unable to create temp dir");
} }
DATA_DIR = QDir(tempDir.path());
//auto files = JlCompress::getFileList(zipData); //auto files = JlCompress::getFileList(zipData);
auto files = JlCompress::extractDir(zipFile.fileName(), DATA_DIR.path()); auto files = JlCompress::extractDir(zipFile.fileName(), DATA_DIR.path());
qDebug() << DATA_DIR.path(); qDebug() << DATA_DIR.path();
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -570,12 +557,14 @@ int main(int argc, char** argv) {
qInstallMessageHandler(messageHandler); qInstallMessageHandler(messageHandler);
QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
if (!DATA_DIR.exists()) {
FileDownloader(DATA_SET, [&](const QByteArray& data) {
qDebug() << "Fetched size " << data.size();
unzipTestData(data);
}).waitForDownload();
}
FileDownloader(DATA_SET, [&](const QByteArray& data) {
qDebug() << "Fetched size " << data.size();
unzipTestData(data);
}).waitForDownload();
QTestWindow::setup(); QTestWindow::setup();
QTestWindow window; QTestWindow window;
app.exec(); app.exec();