mirror of
https://github.com/lubosz/overte.git
synced 2025-04-10 04:52:17 +02:00
Fixing the vizualisation shader for world to cluster space
This commit is contained in:
commit
3bcea4310d
44 changed files with 778 additions and 275 deletions
|
@ -74,6 +74,13 @@ else ()
|
|||
endif ()
|
||||
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 MSVC12) AND (NOT MSVC14))
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
|
21
cmake/externals/gli/CMakeLists.txt
vendored
Normal file
21
cmake/externals/gli/CMakeLists.txt
vendored
Normal 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")
|
4
cmake/externals/glm/CMakeLists.txt
vendored
4
cmake/externals/glm/CMakeLists.txt
vendored
|
@ -3,8 +3,8 @@ set(EXTERNAL_NAME glm)
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.5.4.zip
|
||||
URL_MD5 fab76fc982b256b46208e5c750ed456a
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip
|
||||
URL_MD5 579ac77a3110befa3244d68c0ceb7281
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
12
cmake/macros/TargetGli.cmake
Normal file
12
cmake/macros/TargetGli.cmake
Normal 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()
|
26
cmake/modules/FindGLI.cmake
Normal file
26
cmake/modules/FindGLI.cmake
Normal 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)
|
|
@ -2006,7 +2006,7 @@ void Application::resizeGL() {
|
|||
static qreal lastDevicePixelRatio = 0;
|
||||
qreal devicePixelRatio = _window->devicePixelRatio();
|
||||
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);
|
||||
_offscreenContext->makeCurrent();
|
||||
lastDevicePixelRatio = devicePixelRatio;
|
||||
|
@ -3288,7 +3288,7 @@ void Application::init() {
|
|||
|
||||
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
|
||||
auto dims = item.getDimensions();
|
||||
auto maxSize = glm::max(dims.x, dims.y, dims.z);
|
||||
auto maxSize = glm::compMax(dims);
|
||||
|
||||
if (maxSize <= 0.0f) {
|
||||
return 0.0f;
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
|
||||
#include "Menu.h"
|
||||
|
||||
extern bool DEV_DECIMATE_TEXTURES;
|
||||
|
||||
Menu* Menu::getInstance() {
|
||||
return dynamic_cast<Menu*>(qApp->getWindow()->menuBar());
|
||||
}
|
||||
|
@ -390,6 +392,14 @@ Menu::Menu() {
|
|||
// Developer > Render > LOD Tools
|
||||
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 >>>
|
||||
MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets");
|
||||
auto& atpMigrator = ATPAssetMigrator::getInstance();
|
||||
|
|
|
@ -55,7 +55,7 @@ void SoftAttachmentModel::updateClusterMatrices(glm::vec3 modelPosition, glm::qu
|
|||
|
||||
// TODO: cache these look ups as an optimization
|
||||
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex);
|
||||
glm::mat4 jointMatrix(glm::mat4::_null);
|
||||
glm::mat4 jointMatrix;
|
||||
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride->getJointStateCount()) {
|
||||
jointMatrix = _rigOverride->getJointTransform(jointIndexOverride);
|
||||
} else {
|
||||
|
|
|
@ -277,6 +277,17 @@ void setupPreferences() {
|
|||
preference->setStep(1);
|
||||
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(); };
|
||||
|
|
|
@ -1093,7 +1093,7 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
|
|||
|
||||
// prevent the hand IK targets from intersecting the body capsule
|
||||
glm::vec3 handPosition = params.leftPosition;
|
||||
glm::vec3 displacement(glm::vec3::_null);
|
||||
glm::vec3 displacement;
|
||||
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, 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
|
||||
glm::vec3 handPosition = params.rightPosition;
|
||||
glm::vec3 displacement(glm::vec3::_null);
|
||||
glm::vec3 displacement;
|
||||
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) {
|
||||
handPosition -= displacement;
|
||||
}
|
||||
|
|
|
@ -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_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<int> maxFramesOverDesired("maxFramesOverDesired", DEFAULT_MAX_FRAMES_OVER_DESIRED);
|
||||
Setting::Handle<int> staticDesiredJitterBufferFrames("staticDesiredJitterBufferFrames",
|
||||
|
@ -99,6 +101,8 @@ private:
|
|||
|
||||
AudioClient::AudioClient() :
|
||||
AbstractAudioInterface(),
|
||||
_gateThreshold("audioOutputGateThreshold", DEFAULT_AUDIO_OUTPUT_GATE_THRESHOLD),
|
||||
_gate(this, _gateThreshold.get()),
|
||||
_audioInput(NULL),
|
||||
_desiredInputFormat(),
|
||||
_inputFormat(),
|
||||
|
@ -540,11 +544,48 @@ void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message)
|
|||
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
|
||||
_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) {
|
||||
if (!_muted) {
|
||||
toggleMute();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include <QtCore/qsystemdetection.h>
|
||||
#include <QtCore/QByteArray>
|
||||
|
@ -134,6 +135,9 @@ public:
|
|||
int getOutputStarveDetectionThreshold() { return _outputStarveDetectionThreshold.get(); }
|
||||
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 setOrientationGetter(AudioOrientationGetter orientationGetter) { _orientationGetter = orientationGetter; }
|
||||
|
||||
|
@ -227,6 +231,27 @@ private:
|
|||
float azimuthForSource(const glm::vec3& relativePosition);
|
||||
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;
|
||||
QByteArray firstInputFrame;
|
||||
QAudioInput* _audioInput;
|
||||
|
|
|
@ -12,3 +12,9 @@
|
|||
#include "AudioLogging.h"
|
||||
|
||||
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
|
||||
|
|
|
@ -15,5 +15,6 @@
|
|||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(audio)
|
||||
Q_DECLARE_LOGGING_CATEGORY(audiostream)
|
||||
|
||||
#endif // hifi_AudioLogging_h
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <NodeList.h>
|
||||
|
||||
#include "InboundAudioStream.h"
|
||||
#include "AudioLogging.h"
|
||||
|
||||
const int STARVE_HISTORY_CAPACITY = 50;
|
||||
|
||||
|
@ -174,6 +175,9 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
|||
_currentJitterBufferFrames = 0;
|
||||
|
||||
_oldFramesDropped += framesToDrop;
|
||||
|
||||
qCDebug(audiostream, "Dropped %d frames", framesToDrop);
|
||||
qCDebug(audiostream, "Resetted current jitter frames");
|
||||
}
|
||||
|
||||
framesAvailableChanged();
|
||||
|
@ -228,6 +232,9 @@ int InboundAudioStream::writeDroppableSilentSamples(int silentSamples) {
|
|||
_currentJitterBufferFrames -= numSilentFramesToDrop;
|
||||
_silentFramesDropped += numSilentFramesToDrop;
|
||||
|
||||
qCDebug(audiostream, "Dropped %d silent frames", numSilentFramesToDrop);
|
||||
qCDebug(audiostream, "Set current jitter frames to %d", _currentJitterBufferFrames);
|
||||
|
||||
_framesAvailableStat.reset();
|
||||
}
|
||||
|
||||
|
@ -308,6 +315,8 @@ void InboundAudioStream::framesAvailableChanged() {
|
|||
|
||||
if (_framesAvailableStat.getElapsedUsecs() >= FRAMES_AVAILABLE_STAT_WINDOW_USECS) {
|
||||
_currentJitterBufferFrames = (int)ceil(_framesAvailableStat.getAverage());
|
||||
qCDebug(audiostream, "Set current jitter frames to %d", _currentJitterBufferFrames);
|
||||
|
||||
_framesAvailableStat.reset();
|
||||
}
|
||||
}
|
||||
|
@ -355,6 +364,7 @@ void InboundAudioStream::setToStarved() {
|
|||
// make sure _desiredJitterBufferFrames does not become lower here
|
||||
if (calculatedJitterBufferFrames >= _desiredJitterBufferFrames) {
|
||||
_desiredJitterBufferFrames = calculatedJitterBufferFrames;
|
||||
qCDebug(audiostream, "Set desired jitter frames to %d", _desiredJitterBufferFrames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -444,6 +454,7 @@ void InboundAudioStream::packetReceivedUpdateTimingStats() {
|
|||
/ (float)AudioConstants::NETWORK_FRAME_USECS);
|
||||
if (calculatedJitterBufferFrames < _desiredJitterBufferFrames) {
|
||||
_desiredJitterBufferFrames = calculatedJitterBufferFrames;
|
||||
qCDebug(audiostream, "Set desired jitter frames to %d", _desiredJitterBufferFrames);
|
||||
}
|
||||
_timeGapStatsForDesiredReduction.clearNewStatsAvailableFlag();
|
||||
}
|
||||
|
|
|
@ -96,6 +96,11 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
|
|||
checkFading();
|
||||
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
float largestDiameter = glm::compMax(dimensions);
|
||||
|
||||
|
||||
// DependencyManager::get<DeferredLightingEffect>()->addLight(_light);
|
||||
|
||||
|
@ -146,7 +151,7 @@ void RenderableLightEntityItem::updateRenderItemFromEntity(LightPayload* lightPa
|
|||
}
|
||||
|
||||
glm::vec3 dimensions = entity->getDimensions();
|
||||
float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z);
|
||||
float largestDiameter = glm::compMax(dimensions);
|
||||
light->setMaximumRadius(largestDiameter / 2.0f);
|
||||
|
||||
light->setColor(toGlm(entity->getXColor()));
|
||||
|
|
|
@ -299,7 +299,7 @@ bool RenderableModelEntityItem::getAnimationFrame() {
|
|||
if (index < translations.size()) {
|
||||
translationMat = glm::translate(translations[index]);
|
||||
}
|
||||
glm::mat4 rotationMat(glm::mat4::_null);
|
||||
glm::mat4 rotationMat;
|
||||
if (index < rotations.size()) {
|
||||
rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation);
|
||||
} else {
|
||||
|
|
|
@ -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
|
||||
float distanceToEntity = glm::distance(origin, getPosition());
|
||||
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::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/extented_min_max.hpp>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QObject>
|
||||
|
@ -221,7 +220,7 @@ 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; }
|
||||
bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); }
|
||||
|
|
|
@ -49,7 +49,7 @@ void LightEntityItem::setDimensions(const glm::vec3& value) {
|
|||
const float width = length * glm::sin(glm::radians(_cutoff));
|
||||
EntityItem::setDimensions(glm::vec3(width, width, length));
|
||||
} else {
|
||||
float maxDimension = glm::max(value.x, value.y, value.z);
|
||||
float maxDimension = glm::compMax(value);
|
||||
EntityItem::setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ void LightEntityItem::setIsSpotlight(bool value) {
|
|||
const float width = length * glm::sin(glm::radians(_cutoff));
|
||||
setDimensions(glm::vec3(width, width, length));
|
||||
} else {
|
||||
float maxDimension = glm::max(dimensions.x, dimensions.y, dimensions.z);
|
||||
float maxDimension = glm::compMax(dimensions);
|
||||
setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
|
||||
}
|
||||
_lightPropertiesChanged = true;
|
||||
|
|
|
@ -4,6 +4,7 @@ link_hifi_libraries(shared gl gpu)
|
|||
GroupSources("src")
|
||||
|
||||
target_opengl()
|
||||
target_nsight()
|
||||
|
||||
if (NOT ANDROID)
|
||||
target_glew()
|
||||
|
|
|
@ -315,7 +315,6 @@ void GLBackend::render(const Batch& batch) {
|
|||
|
||||
|
||||
void GLBackend::syncCache() {
|
||||
recycle();
|
||||
syncTransformStateCache();
|
||||
syncPipelineStateCache();
|
||||
syncInputStateCache();
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <GPUIdent.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <fstream>
|
||||
|
@ -933,9 +935,28 @@ void makeProgramBindings(ShaderObject& shaderObject) {
|
|||
(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;
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,12 @@ Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
|
|||
|
||||
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();
|
||||
ComparisonFunction comparisonFuncFromGL(GLenum func);
|
||||
State::StencilOp stencilOpFromGL(GLenum stencilOp);
|
||||
|
|
|
@ -292,3 +292,14 @@ void GLTexture::postTransfer() {
|
|||
void GLTexture::initTextureTransferHelper() {
|
||||
_textureTransferHelper = std::make_shared<GLTextureTransferHelper>();
|
||||
}
|
||||
|
||||
void GLTexture::startTransfer() {
|
||||
createTexture();
|
||||
}
|
||||
|
||||
void GLTexture::finishTransfer() {
|
||||
if (_gpuObject.isAutogenerateMips()) {
|
||||
generateMips();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "GLShared.h"
|
||||
#include "GLTextureTransfer.h"
|
||||
#include "GLBackend.h"
|
||||
#include "GLTexelFormat.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
|
@ -19,6 +20,7 @@ struct GLFilterMode {
|
|||
GLint magFilter;
|
||||
};
|
||||
|
||||
|
||||
class GLTexture : public GLObject<Texture> {
|
||||
public:
|
||||
static const uint16_t INVALID_MIP { (uint16_t)-1 };
|
||||
|
@ -162,11 +164,13 @@ public:
|
|||
|
||||
bool isOverMaxMemory() const;
|
||||
|
||||
protected:
|
||||
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
|
||||
|
||||
static const size_t CUBE_NUM_FACES = 6;
|
||||
static const GLenum CUBE_FACE_LAYOUT[6];
|
||||
static const GLFilterMode FILTER_MODES[Sampler::NUM_FILTERS];
|
||||
static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES];
|
||||
protected:
|
||||
|
||||
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);
|
||||
|
||||
void setSyncState(GLSyncState syncState) { _syncState = syncState; }
|
||||
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
|
||||
|
||||
void createTexture();
|
||||
|
||||
virtual void allocateStorage() const = 0;
|
||||
virtual void updateSize() const = 0;
|
||||
virtual void transfer() const = 0;
|
||||
virtual void syncSampler() const = 0;
|
||||
virtual void generateMips() const = 0;
|
||||
virtual void withPreservedTexture(std::function<void()> f) const = 0;
|
||||
|
@ -199,6 +201,11 @@ protected:
|
|||
protected:
|
||||
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:
|
||||
|
||||
GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable);
|
||||
|
|
|
@ -13,6 +13,18 @@
|
|||
#include "GLShared.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::gl;
|
||||
|
||||
|
@ -36,82 +48,126 @@ GLTextureTransferHelper::~GLTextureTransferHelper() {
|
|||
|
||||
void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& 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);
|
||||
queueItem(package);
|
||||
Lock lock(_mutex);
|
||||
_pendingTextures.push_back(texturePointer);
|
||||
#else
|
||||
object->withPreservedTexture([&] {
|
||||
do_transfer(*object);
|
||||
});
|
||||
for (object->startTransfer(); object->continueTransfer(); ) { }
|
||||
object->finishTransfer();
|
||||
object->_contentStamp = texturePointer->getDataStamp();
|
||||
object->setSyncState(GLSyncState::Transferred);
|
||||
#endif
|
||||
}
|
||||
|
||||
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::do_transfer(GLTexture& texture) {
|
||||
texture.createTexture();
|
||||
texture.transfer();
|
||||
texture.updateSize();
|
||||
Backend::decrementTextureGPUTransferCount();
|
||||
}
|
||||
|
||||
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
_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
|
||||
for (auto package : messages) {
|
||||
TexturePointer texturePointer = package.texture.lock();
|
||||
// Texture no longer exists, move on to the next
|
||||
if (!texturePointer) {
|
||||
}
|
||||
|
||||
bool GLTextureTransferHelper::process() {
|
||||
#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;
|
||||
}
|
||||
|
||||
if (package.fence) {
|
||||
auto result = glClientWaitSync(package.fence, 0, 0);
|
||||
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
|
||||
// Minimum sleep
|
||||
QThread::usleep(1);
|
||||
result = glClientWaitSync(package.fence, 0, 0);
|
||||
}
|
||||
assert(GL_CONDITION_SATISFIED == result || GL_ALREADY_SIGNALED == result);
|
||||
glDeleteSync(package.fence);
|
||||
package.fence = 0;
|
||||
}
|
||||
|
||||
GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer);
|
||||
|
||||
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);
|
||||
gltexture->finishTransfer();
|
||||
glNamedFramebufferTexture(_readFramebuffer, GL_COLOR_ATTACHMENT0, gltexture->_id, 0);
|
||||
glBlitNamedFramebuffer(_readFramebuffer, _drawFramebuffer, 0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
clientWait();
|
||||
gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp();
|
||||
gltexture->updateSize();
|
||||
gltexture->setSyncState(gpu::gl::GLSyncState::Transferred);
|
||||
Backend::decrementTextureGPUTransferCount();
|
||||
#ifdef HAVE_NSIGHT
|
||||
// Mark the texture as transferred
|
||||
nvtxRangeEnd(_map[texture]);
|
||||
_map.erase(texture);
|
||||
#endif
|
||||
_textureIterator = _transferringTextures.erase(_textureIterator);
|
||||
}
|
||||
#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
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -23,27 +23,38 @@
|
|||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
struct TextureTransferPackage {
|
||||
std::weak_ptr<Texture> texture;
|
||||
GLsync fence;
|
||||
};
|
||||
using TextureList = std::list<TexturePointer>;
|
||||
using TextureListIterator = TextureList::iterator;
|
||||
|
||||
class GLTextureTransferHelper : public GenericQueueThread<TextureTransferPackage> {
|
||||
class GLTextureTransferHelper : public GenericThread {
|
||||
public:
|
||||
using Pointer = std::shared_ptr<GLTextureTransferHelper>;
|
||||
GLTextureTransferHelper();
|
||||
~GLTextureTransferHelper();
|
||||
void transferTexture(const gpu::TexturePointer& texturePointer);
|
||||
void postTransfer(const gpu::TexturePointer& texturePointer);
|
||||
|
||||
protected:
|
||||
void setup() override;
|
||||
void shutdown() override;
|
||||
bool processQueueItems(const Queue& messages) override;
|
||||
void do_transfer(GLTexture& texturePointer);
|
||||
bool process() override;
|
||||
|
||||
private:
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
::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
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -46,10 +46,10 @@ public:
|
|||
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, GL41Texture* original);
|
||||
|
||||
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 updateSize() const override;
|
||||
void transfer() const override;
|
||||
void syncSampler() const override;
|
||||
void generateMips() const override;
|
||||
void withPreservedTexture(std::function<void()> f) const override;
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
void GL41Backend::GL41Texture::withPreservedTexture(std::function<void()> f) const {
|
||||
void GL41Texture::withPreservedTexture(std::function<void()> f) const {
|
||||
GLint boundTex = -1;
|
||||
switch (_target) {
|
||||
case GL_TEXTURE_2D:
|
||||
|
@ -64,14 +64,14 @@ void GL41Backend::GL41Texture::withPreservedTexture(std::function<void()> f) con
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GL41Backend::GL41Texture::generateMips() const {
|
||||
void GL41Texture::generateMips() const {
|
||||
withPreservedTexture([&] {
|
||||
glGenerateMipmap(_target);
|
||||
});
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GL41Backend::GL41Texture::allocateStorage() const {
|
||||
void GL41Texture::allocateStorage() const {
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
|
||||
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
@ -94,7 +94,7 @@ void GL41Backend::GL41Texture::allocateStorage() const {
|
|||
}
|
||||
}
|
||||
|
||||
void GL41Backend::GL41Texture::updateSize() const {
|
||||
void GL41Texture::updateSize() const {
|
||||
setSize(_virtualSize);
|
||||
if (!_id) {
|
||||
return;
|
||||
|
@ -130,7 +130,7 @@ void GL41Backend::GL41Texture::updateSize() const {
|
|||
}
|
||||
|
||||
// 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);
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
|
||||
//GLenum target = getFaceTargets()[face];
|
||||
|
@ -140,15 +140,9 @@ void GL41Backend::GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) cons
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
// This should never happen on the main thread
|
||||
// Move content bits from the CPU to the GPU
|
||||
void GL41Backend::GL41Texture::transfer() const {
|
||||
void GL41Texture::startTransfer() {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
//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;
|
||||
}
|
||||
Parent::startTransfer();
|
||||
|
||||
glBindTexture(_target, _id);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
@ -175,38 +169,16 @@ void GL41Backend::GL41Texture::transfer() const {
|
|||
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);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
|
|
@ -18,6 +18,29 @@ namespace gpu { namespace gl45 {
|
|||
|
||||
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 {
|
||||
using Parent = GLBackend;
|
||||
// Context Backend static interface required
|
||||
|
@ -29,19 +52,25 @@ public:
|
|||
|
||||
class GL45Texture : public GLTexture {
|
||||
using Parent = GLTexture;
|
||||
GLuint allocate(const Texture& texture);
|
||||
static GLuint allocate(const Texture& texture);
|
||||
public:
|
||||
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();
|
||||
|
||||
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 allocateMip(uint16_t mipLevel, uint8_t face = 0) const;
|
||||
void allocateStorage() const override;
|
||||
void updateSize() const override;
|
||||
void transfer() const override;
|
||||
void syncSampler() const override;
|
||||
void generateMips() const override;
|
||||
void withPreservedTexture(std::function<void()> f) const override;
|
||||
|
||||
TransferState _transferState;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
//
|
||||
#include "GL45Backend.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
|
@ -21,10 +24,111 @@ using namespace gpu;
|
|||
using namespace gpu::gl;
|
||||
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;
|
||||
|
||||
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) {
|
||||
Backend::incrementTextureGPUCount();
|
||||
GLuint result;
|
||||
glCreateTextures(getGLTextureType(texture), 1, &result);
|
||||
return result;
|
||||
|
@ -34,26 +138,38 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) {
|
|||
return GL45Texture::getId<GL45Texture>(*this, texture, transfer);
|
||||
}
|
||||
|
||||
GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
|
||||
return GL45Texture::sync<GL45Texture>(*this, texture, transfer);
|
||||
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
|
||||
: 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)
|
||||
: GLTexture(backend, texture, allocate(texture), transferrable) {}
|
||||
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original)
|
||||
: GLTexture(backend, texture, allocate(texture), original), _transferState(*this) { }
|
||||
|
||||
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original)
|
||||
: GLTexture(backend, texture, allocate(texture), original) {}
|
||||
GL45Texture::~GL45Texture() {
|
||||
// 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();
|
||||
}
|
||||
|
||||
void GL45Backend::GL45Texture::generateMips() const {
|
||||
void GL45Texture::generateMips() const {
|
||||
glGenerateTextureMipmap(_id);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GL45Backend::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);
|
||||
|
@ -66,7 +182,7 @@ void GL45Backend::GL45Texture::allocateStorage() const {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GL45Backend::GL45Texture::updateSize() const {
|
||||
void GL45Texture::updateSize() const {
|
||||
setSize(_virtualSize);
|
||||
if (!_id) {
|
||||
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 GL45Backend::GL45Texture::transferMip(uint16_t mipLevel, uint8_t face) const {
|
||||
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
|
||||
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();
|
||||
void GL45Texture::startTransfer() {
|
||||
Parent::startTransfer();
|
||||
_transferState.updateSparse();
|
||||
_transferState.updateMip();
|
||||
}
|
||||
|
||||
// This should never happen on the main thread
|
||||
// Move content bits from the CPU to the GPU
|
||||
void GL45Backend::GL45Texture::transfer() const {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
//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;
|
||||
bool GL45Texture::continueTransfer() {
|
||||
static std::vector<uint8_t> buffer;
|
||||
if (buffer.empty()) {
|
||||
buffer.resize(DEFAULT_PAGE_BUFFER_SIZE);
|
||||
}
|
||||
uvec3 pageSize = _transferState.currentPageSize();
|
||||
uvec3 offset = _transferState._mipOffset;
|
||||
|
||||
if (_downsampleSource._texture) {
|
||||
GLuint fbo { 0 };
|
||||
glCreateFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
// 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();
|
||||
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;
|
||||
#if SPARSE_TEXTURES
|
||||
if (_transferState._mipLevel <= _transferState._maxSparseLevel) {
|
||||
glTexturePageCommitmentEXT(_id, _transferState._mipLevel,
|
||||
offset.x, offset.y, _transferState._face,
|
||||
pageSize.x, pageSize.y, pageSize.z,
|
||||
GL_TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
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(gpugl45logging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported";
|
||||
break;
|
||||
if (_transferState._srcPointer) {
|
||||
// Transfer the mip data
|
||||
_transferState.populatePage(buffer);
|
||||
if (GL_TEXTURE_2D == _target) {
|
||||
glTextureSubImage2D(_id, _transferState._mipLevel,
|
||||
offset.x, offset.y,
|
||||
pageSize.x, pageSize.y,
|
||||
_transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]);
|
||||
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
||||
auto target = CUBE_FACE_LAYOUT[_transferState._face];
|
||||
// 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());
|
||||
glTextureSubImage2DEXT(_id, target, _transferState._mipLevel,
|
||||
offset.x, offset.y,
|
||||
pageSize.x, pageSize.y,
|
||||
_transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]);
|
||||
}
|
||||
}
|
||||
if (_gpuObject.isAutogenerateMips()) {
|
||||
glGenerateTextureMipmap(_id);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
serverWait();
|
||||
return _transferState.increment();
|
||||
}
|
||||
|
||||
void GL45Backend::GL45Texture::syncSampler() const {
|
||||
|
|
|
@ -18,12 +18,15 @@
|
|||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
#include <QImageReader>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/random.hpp>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
|
||||
#include <Finally.h>
|
||||
|
@ -307,6 +310,24 @@ ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QByteArra
|
|||
_url(url),
|
||||
_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() {
|
||||
|
|
|
@ -22,6 +22,13 @@ using namespace gpu;
|
|||
// FIXME: Declare this to enable compression
|
||||
//#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) {
|
||||
_textureSource = textureSource;
|
||||
|
@ -53,7 +60,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
|
|||
}
|
||||
|
||||
const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
|
||||
QImage image = srcImage;
|
||||
QImage image = processSourceImage(srcImage);
|
||||
validAlpha = false;
|
||||
alphaAsMask = true;
|
||||
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) {
|
||||
QImage image = srcImage;
|
||||
QImage image = processSourceImage(srcImage);
|
||||
|
||||
if (image.format() != 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) {
|
||||
QImage image = srcImage;
|
||||
|
||||
QImage image = processSourceImage(srcImage);
|
||||
|
||||
if (image.format() != 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) {
|
||||
QImage image = srcImage;
|
||||
QImage image = processSourceImage(srcImage);
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != 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) {
|
||||
QImage image = srcImage;
|
||||
QImage image = processSourceImage(srcImage);
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != 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) {
|
||||
QImage image = srcImage;
|
||||
QImage image = processSourceImage(srcImage);
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != 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* theTexture = nullptr;
|
||||
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
||||
QImage image = srcImage;
|
||||
QImage image = processSourceImage(srcImage);
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ inline btTransform glmToBullet(const glm::mat4& m) {
|
|||
}
|
||||
|
||||
inline glm::mat4 bulletToGLM(const btTransform& t) {
|
||||
glm::mat4 m(glm::mat4::_null);
|
||||
glm::mat4 m;
|
||||
|
||||
const btMatrix3x3& basis = t.getBasis();
|
||||
// copy over 3x3 part
|
||||
|
|
|
@ -8,4 +8,4 @@ if (WIN32)
|
|||
endif()
|
||||
|
||||
target_zlib()
|
||||
target_nsight()
|
||||
target_nsight()
|
|
@ -9,8 +9,6 @@
|
|||
// 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 "AACube.h"
|
||||
#include "Extents.h"
|
||||
|
@ -25,7 +23,7 @@ AACube::AACube(const Extents& other) :
|
|||
_corner(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) :
|
||||
|
@ -479,8 +477,8 @@ AACube& AACube::operator += (const glm::vec3& point) {
|
|||
|
||||
glm::vec3 scaleOld = oldMaximumPoint - _corner;
|
||||
glm::vec3 scalePoint = point - _corner;
|
||||
_scale = glm::max(_scale, scalePoint.x, scalePoint.y, scalePoint.z);
|
||||
_scale = glm::max(_scale, scaleOld.x, scaleOld.y, scaleOld.z);
|
||||
_scale = std::max(_scale, glm::compMax(scalePoint));
|
||||
_scale = std::max(_scale, glm::compMax(scaleOld));
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#define hifi_Extents_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/extented_min_max.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
||||
#include <QDebug>
|
||||
#include "StreamUtils.h"
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
void transform(const Transform& transform);
|
||||
|
||||
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
|
||||
Extents getRotated(const glm::quat& rotation) const {
|
||||
|
|
|
@ -203,19 +203,19 @@ inline float lerp(float x, float y, float a) {
|
|||
|
||||
// vec2 lerp - linear interpolate
|
||||
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);
|
||||
}
|
||||
|
||||
// vec3 lerp - linear interpolate
|
||||
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);
|
||||
}
|
||||
|
||||
// vec4 lerp - linear interpolate
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -797,7 +797,7 @@ void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) {
|
|||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalVelocity() const {
|
||||
glm::vec3 result(glm::vec3::_null);
|
||||
glm::vec3 result;
|
||||
_velocityLock.withReadLock([&] {
|
||||
result = _velocity;
|
||||
});
|
||||
|
@ -811,7 +811,7 @@ void SpatiallyNestable::setLocalVelocity(const glm::vec3& velocity) {
|
|||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalAngularVelocity() const {
|
||||
glm::vec3 result(glm::vec3::_null);
|
||||
glm::vec3 result;
|
||||
_angularVelocityLock.withReadLock([&] {
|
||||
result = _angularVelocity;
|
||||
});
|
||||
|
|
|
@ -14,6 +14,9 @@ link_hifi_libraries(shared octree gl gpu gpu-gl render model model-networking ne
|
|||
|
||||
package_libraries_for_deployment()
|
||||
|
||||
target_gli()
|
||||
target_glm()
|
||||
|
||||
target_zlib()
|
||||
add_dependency_external_projects(quazip)
|
||||
find_package(QuaZip REQUIRED)
|
||||
|
|
70
tests/render-texture-load/src/GLIHelpers.cpp
Normal file
70
tests/render-texture-load/src/GLIHelpers.cpp
Normal 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();
|
||||
}
|
47
tests/render-texture-load/src/GLIHelpers.h
Normal file
47
tests/render-texture-load/src/GLIHelpers.h
Normal 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
|
|
@ -11,9 +11,6 @@
|
|||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <gl/Context.h>
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
@ -41,6 +38,7 @@
|
|||
#include <quazip5/JlCompress.h>
|
||||
|
||||
|
||||
#include "GLIHelpers.h"
|
||||
#include <shared/RateCounter.h>
|
||||
#include <AssetClient.h>
|
||||
#include <PathUtils.h>
|
||||
|
@ -55,15 +53,15 @@
|
|||
#include <TextureCache.h>
|
||||
#include <FramebufferCache.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <RenderShadowTask.h>
|
||||
#include <RenderDeferredTask.h>
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <gl/Context.h>
|
||||
|
||||
extern QThread* RENDER_THREAD;
|
||||
|
||||
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 {
|
||||
Q_OBJECT
|
||||
|
@ -81,7 +79,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void fileDownloaded(QNetworkReply* pReply) {
|
||||
_handler(pReply->readAll());
|
||||
pReply->deleteLater();
|
||||
|
@ -132,8 +130,6 @@ public:
|
|||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
_backend = _gpuContext->getBackend();
|
||||
_context.makeCurrent();
|
||||
DependencyManager::get<DeferredLightingEffect>()->init();
|
||||
_context.makeCurrent();
|
||||
initContext.create();
|
||||
_context.doneCurrent();
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
|
@ -191,7 +187,7 @@ public:
|
|||
_gpuContext->executeFrame(frame);
|
||||
|
||||
{
|
||||
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
gpu::Batch presentBatch;
|
||||
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
|
||||
class QTestWindow : public QWindow {
|
||||
public:
|
||||
|
@ -296,7 +282,6 @@ public:
|
|||
//DependencyManager::registerInheritance<SpatialParentFinder, ParentFinder>();
|
||||
DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent);
|
||||
DependencyManager::set<DeferredLightingEffect>();
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<TextureCache>();
|
||||
DependencyManager::set<FramebufferCache>();
|
||||
|
@ -316,7 +301,7 @@ public:
|
|||
_currentTexture = _textures.end();
|
||||
{
|
||||
QStringList stringList;
|
||||
QFile textFile("h:/textures/loads.txt");
|
||||
QFile textFile(DATA_DIR.path() + "/loads.txt");
|
||||
textFile.open(QFile::ReadOnly);
|
||||
//... (open the file for reading, etc.)
|
||||
QTextStream textStream(&textFile);
|
||||
|
@ -332,8 +317,7 @@ public:
|
|||
auto index = s.indexOf(" ");
|
||||
QString timeStr = s.left(index);
|
||||
auto time = timeStr.toUInt();
|
||||
QString path = s.right(s.length() - index).trimmed();
|
||||
path = fileForPath(path);
|
||||
QString path = DATA_DIR.path() + "/" + s.right(s.length() - index).trimmed();
|
||||
qDebug() << "Path " << path;
|
||||
if (!QFileInfo(path).exists()) {
|
||||
continue;
|
||||
|
@ -341,7 +325,7 @@ public:
|
|||
_textureLoads.push({ time, path, s });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
installEventFilter(this);
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(2);
|
||||
QThread::currentThread()->setPriority(QThread::HighestPriority);
|
||||
|
@ -436,7 +420,7 @@ private:
|
|||
QSize windowSize = _size;
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
framebufferCache->setFrameBufferSize(windowSize);
|
||||
|
||||
|
||||
// Final framebuffer that will be handled to the display-plugin
|
||||
render();
|
||||
|
||||
|
@ -462,8 +446,9 @@ private:
|
|||
qDebug() << "Missing file " << front.file;
|
||||
} else {
|
||||
qDebug() << "Loading " << front.src;
|
||||
auto file = front.file.toLocal8Bit().toStdString();
|
||||
processTexture(file.c_str());
|
||||
_textures.push_back(DependencyManager::get<TextureCache>()->getImageTexture(front.file));
|
||||
_currentTexture = _textures.begin();
|
||||
}
|
||||
_textureLoads.pop();
|
||||
if (_textureLoads.empty()) {
|
||||
|
@ -481,7 +466,7 @@ private:
|
|||
});
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
auto framebuffer = DependencyManager::get<FramebufferCache>()->getFramebuffer();
|
||||
|
||||
|
||||
gpu::doInBatch(gpuContext, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(framebuffer);
|
||||
|
@ -494,8 +479,7 @@ private:
|
|||
}
|
||||
if (_currentTexture == _textures.end()) {
|
||||
_currentTexture = _textures.begin();
|
||||
}
|
||||
|
||||
}
|
||||
if (_currentTexture != _textures.end()) {
|
||||
batch.setResourceTexture(0, *_currentTexture);
|
||||
}
|
||||
|
@ -505,7 +489,7 @@ private:
|
|||
|
||||
auto frame = gpuContext->endFrame();
|
||||
frame->framebuffer = framebuffer;
|
||||
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer){
|
||||
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
|
||||
DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer);
|
||||
};
|
||||
_renderThread.submitFrame(frame);
|
||||
|
@ -546,20 +530,23 @@ hifi.gpu=true
|
|||
)V0G0N";
|
||||
|
||||
void unzipTestData(const QByteArray& zipData) {
|
||||
DOWNLOAD_DIR = new QTemporaryDir();
|
||||
QTemporaryDir& tempDir = *DOWNLOAD_DIR;
|
||||
QTemporaryFile zipFile;
|
||||
|
||||
if (zipFile.open()) {
|
||||
zipFile.write(zipData);
|
||||
zipFile.close();
|
||||
}
|
||||
qDebug() << zipFile.fileName();
|
||||
if (!DATA_DIR.isValid()) {
|
||||
if (!tempDir.isValid()) {
|
||||
qFatal("Unable to create temp dir");
|
||||
}
|
||||
|
||||
DATA_DIR = QDir(tempDir.path());
|
||||
|
||||
//auto files = JlCompress::getFileList(zipData);
|
||||
auto files = JlCompress::extractDir(zipFile.fileName(), DATA_DIR.path());
|
||||
qDebug() << DATA_DIR.path();
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
@ -570,12 +557,14 @@ int main(int argc, char** argv) {
|
|||
qInstallMessageHandler(messageHandler);
|
||||
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 window;
|
||||
app.exec();
|
||||
|
|
Loading…
Reference in a new issue