Fixing the vizualisation shader for world to cluster space

This commit is contained in:
samcake 2016-09-10 10:41:18 -07:00
commit 3bcea4310d
44 changed files with 778 additions and 275 deletions

View file

@ -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
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)
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

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;
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;

View file

@ -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();

View file

@ -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 {

View file

@ -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(); };

View file

@ -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;
}

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_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();

View file

@ -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;

View file

@ -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

View file

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

View file

@ -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();
}

View file

@ -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()));

View file

@ -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 {

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
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);

View file

@ -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); }

View file

@ -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;

View file

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

View file

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

View file

@ -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;

View file

@ -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);

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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
};
} }

View file

@ -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;

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) {}
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 {

View file

@ -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;
};

View file

@ -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 {

View file

@ -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() {

View file

@ -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);
}

View file

@ -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

View file

@ -8,4 +8,4 @@ if (WIN32)
endif()
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
//
#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);
}

View file

@ -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 {

View file

@ -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);
}

View file

@ -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;
});

View file

@ -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)

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 <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();