Merge branch 'master' of github.com:highfidelity/hifi into tablet-webView2.0

This commit is contained in:
Dante Ruiz 2017-04-01 00:58:37 +01:00
commit b10f491c6e
48 changed files with 1017 additions and 575 deletions

View file

@ -187,7 +187,7 @@ void AvatarMixer::start() {
// NOTE: nodeData->getAvatar() might be side effected, must be called when access to node/nodeData
// is guarenteed to not be accessed by other thread
// is guaranteed to not be accessed by other thread
void AvatarMixer::manageDisplayName(const SharedNodePointer& node) {
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
if (nodeData && nodeData->getAvatarSessionDisplayNameMustChange()) {

View file

@ -49,7 +49,7 @@ private:
bool _stop { false };
};
// Slave pool for audio mixers
// Slave pool for avatar mixers
// AvatarMixerSlavePool is not thread-safe! It should be instantiated and used from a single thread.
class AvatarMixerSlavePool {
using Queue = tbb::concurrent_queue<SharedNodePointer>;

View file

@ -1,7 +1,6 @@
import QtQuick 2.5
import QtQuick.Controls 1.4 as Controls
import "../../qml/menus"
import "../../qml/controls-uit"
import "../../qml/styles-uit"

View file

@ -180,6 +180,7 @@
#include "FrameTimingsScriptingInterface.h"
#include <GPUIdent.h>
#include <gl/GLHelpers.h>
#include <src/scripting/LimitlessVoiceRecognitionScriptingInterface.h>
#include <EntityScriptClient.h>
#include <ModelScriptingInterface.h>
@ -522,7 +523,9 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::set<OffscreenQmlSurfaceCache>();
DependencyManager::set<EntityScriptClient>();
DependencyManager::set<EntityScriptServerLogClient>();
DependencyManager::set<LimitlessVoiceRecognitionScriptingInterface>();
DependencyManager::set<OctreeStatsProvider>(nullptr, qApp->getOcteeSceneStats());
return previousSessionCrashed;
}
@ -550,7 +553,7 @@ const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false;
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = true;
const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false;
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
QApplication(argc, argv),
@ -4572,6 +4575,8 @@ void Application::update(float deltaTime) {
}
AnimDebugDraw::getInstance().update();
DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>()->update();
}
void Application::sendAvatarViewFrustum() {
@ -5518,6 +5523,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>().data());
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine, steamClient.get()));
}

View file

@ -0,0 +1,91 @@
#include <QJsonDocument>
#include <QJsonArray>
#include <src/InterfaceLogging.h>
#include <src/ui/AvatarInputs.h>
#include "LimitlessConnection.h"
#include "LimitlessVoiceRecognitionScriptingInterface.h"
LimitlessConnection::LimitlessConnection() :
_streamingAudioForTranscription(false)
{
}
void LimitlessConnection::startListening(QString authCode) {
_transcribeServerSocket.reset(new QTcpSocket(this));
connect(_transcribeServerSocket.get(), &QTcpSocket::readyRead, this,
&LimitlessConnection::transcriptionReceived);
connect(_transcribeServerSocket.get(), &QTcpSocket::disconnected, this, [this](){stopListening();});
static const auto host = "gserv_devel.studiolimitless.com";
_transcribeServerSocket->connectToHost(host, 1407);
_transcribeServerSocket->waitForConnected();
QString requestHeader = QString::asprintf("Authorization: %s\r\nfs: %i\r\n",
authCode.toLocal8Bit().data(), AudioConstants::SAMPLE_RATE);
qCDebug(interfaceapp) << "Sending Limitless Audio Stream Request: " << requestHeader;
_transcribeServerSocket->write(requestHeader.toLocal8Bit());
_transcribeServerSocket->waitForBytesWritten();
}
void LimitlessConnection::stopListening() {
emit onFinishedSpeaking(_currentTranscription);
_streamingAudioForTranscription = false;
_currentTranscription = "";
if (!isConnected())
return;
_transcribeServerSocket->close();
disconnect(_transcribeServerSocket.get(), &QTcpSocket::readyRead, this,
&LimitlessConnection::transcriptionReceived);
_transcribeServerSocket.release()->deleteLater();
disconnect(DependencyManager::get<AudioClient>().data(), &AudioClient::inputReceived, this,
&LimitlessConnection::audioInputReceived);
qCDebug(interfaceapp) << "Connection to Limitless Voice Server closed.";
}
void LimitlessConnection::audioInputReceived(const QByteArray& inputSamples) {
if (isConnected()) {
_transcribeServerSocket->write(inputSamples.data(), inputSamples.size());
_transcribeServerSocket->waitForBytesWritten();
}
}
void LimitlessConnection::transcriptionReceived() {
while (_transcribeServerSocket && _transcribeServerSocket->bytesAvailable() > 0) {
const QByteArray data = _transcribeServerSocket->readAll();
_serverDataBuffer.append(data);
int begin = _serverDataBuffer.indexOf('<');
int end = _serverDataBuffer.indexOf('>');
while (begin > -1 && end > -1) {
const int len = end - begin;
const QByteArray serverMessage = _serverDataBuffer.mid(begin+1, len-1);
if (serverMessage.contains("1407")) {
qCDebug(interfaceapp) << "Limitless Speech Server denied the request.";
// Don't spam the server with further false requests please.
DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>()->setListeningToVoice(true);
stopListening();
return;
} else if (serverMessage.contains("1408")) {
qCDebug(interfaceapp) << "Limitless Audio request authenticated!";
_serverDataBuffer.clear();
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::inputReceived, this,
&LimitlessConnection::audioInputReceived);
return;
}
QJsonObject json = QJsonDocument::fromJson(serverMessage.data()).object();
_serverDataBuffer.remove(begin, len+1);
_currentTranscription = json["alternatives"].toArray()[0].toObject()["transcript"].toString();
emit onReceivedTranscription(_currentTranscription);
if (json["isFinal"] == true) {
qCDebug(interfaceapp) << "Final transcription: " << _currentTranscription;
stopListening();
return;
}
begin = _serverDataBuffer.indexOf('<');
end = _serverDataBuffer.indexOf('>');
}
}
}
bool LimitlessConnection::isConnected() const {
return _transcribeServerSocket.get() && _transcribeServerSocket->isWritable()
&& _transcribeServerSocket->state() != QAbstractSocket::SocketState::UnconnectedState;
}

View file

@ -0,0 +1,44 @@
//
// SpeechRecognitionScriptingInterface.h
// interface/src/scripting
//
// Created by Trevor Berninger on 3/24/17.
// Copyright 2017 Limitless ltd.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_LimitlessConnection_h
#define hifi_LimitlessConnection_h
#include <AudioClient.h>
#include <QObject>
#include <QFuture>
class LimitlessConnection : public QObject {
Q_OBJECT
public:
LimitlessConnection();
Q_INVOKABLE void startListening(QString authCode);
Q_INVOKABLE void stopListening();
std::atomic<bool> _streamingAudioForTranscription;
signals:
void onReceivedTranscription(QString speech);
void onFinishedSpeaking(QString speech);
private:
void transcriptionReceived();
void audioInputReceived(const QByteArray& inputSamples);
bool isConnected() const;
std::unique_ptr<QTcpSocket> _transcribeServerSocket;
QByteArray _serverDataBuffer;
QString _currentTranscription;
};
#endif //hifi_LimitlessConnection_h

View file

@ -0,0 +1,64 @@
//
// SpeechRecognitionScriptingInterface.h
// interface/src/scripting
//
// Created by Trevor Berninger on 3/20/17.
// Copyright 2017 Limitless ltd.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <src/InterfaceLogging.h>
#include <src/ui/AvatarInputs.h>
#include <QtConcurrent/QtConcurrentRun>
#include "LimitlessVoiceRecognitionScriptingInterface.h"
const float LimitlessVoiceRecognitionScriptingInterface::_audioLevelThreshold = 0.33f;
const int LimitlessVoiceRecognitionScriptingInterface::_voiceTimeoutDuration = 2000;
LimitlessVoiceRecognitionScriptingInterface::LimitlessVoiceRecognitionScriptingInterface() :
_shouldStartListeningForVoice(false)
{
_voiceTimer.setSingleShot(true);
connect(&_voiceTimer, &QTimer::timeout, this, &LimitlessVoiceRecognitionScriptingInterface::voiceTimeout);
connect(&_connection, &LimitlessConnection::onReceivedTranscription, this, [this](QString transcription){emit onReceivedTranscription(transcription);});
connect(&_connection, &LimitlessConnection::onFinishedSpeaking, this, [this](QString transcription){emit onFinishedSpeaking(transcription);});
_connection.moveToThread(&_connectionThread);
_connectionThread.setObjectName("Limitless Connection");
_connectionThread.start();
}
void LimitlessVoiceRecognitionScriptingInterface::update() {
const float audioLevel = AvatarInputs::getInstance()->loudnessToAudioLevel(DependencyManager::get<AudioClient>()->getAudioAverageInputLoudness());
if (_shouldStartListeningForVoice) {
if (_connection._streamingAudioForTranscription) {
if (audioLevel > _audioLevelThreshold) {
if (_voiceTimer.isActive()) {
_voiceTimer.stop();
}
} else if (!_voiceTimer.isActive()){
_voiceTimer.start(_voiceTimeoutDuration);
}
} else if (audioLevel > _audioLevelThreshold) {
// to make sure invoke doesn't get called twice before the method actually gets called
_connection._streamingAudioForTranscription = true;
QMetaObject::invokeMethod(&_connection, "startListening", Q_ARG(QString, authCode));
}
}
}
void LimitlessVoiceRecognitionScriptingInterface::setListeningToVoice(bool listening) {
_shouldStartListeningForVoice = listening;
}
void LimitlessVoiceRecognitionScriptingInterface::setAuthKey(QString key) {
authCode = key;
}
void LimitlessVoiceRecognitionScriptingInterface::voiceTimeout() {
if (_connection._streamingAudioForTranscription) {
QMetaObject::invokeMethod(&_connection, "stopListening");
}
}

View file

@ -0,0 +1,50 @@
//
// SpeechRecognitionScriptingInterface.h
// interface/src/scripting
//
// Created by Trevor Berninger on 3/20/17.
// Copyright 2017 Limitless ltd.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_SpeechRecognitionScriptingInterface_h
#define hifi_SpeechRecognitionScriptingInterface_h
#include <AudioClient.h>
#include <QObject>
#include <QFuture>
#include "LimitlessConnection.h"
class LimitlessVoiceRecognitionScriptingInterface : public QObject, public Dependency {
Q_OBJECT
public:
LimitlessVoiceRecognitionScriptingInterface();
void update();
QString authCode;
public slots:
void setListeningToVoice(bool listening);
void setAuthKey(QString key);
signals:
void onReceivedTranscription(QString speech);
void onFinishedSpeaking(QString speech);
private:
bool _shouldStartListeningForVoice;
static const float _audioLevelThreshold;
static const int _voiceTimeoutDuration;
QTimer _voiceTimer;
QThread _connectionThread;
LimitlessConnection _connection;
void voiceTimeout();
};
#endif //hifi_SpeechRecognitionScriptingInterface_h

View file

@ -85,7 +85,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
renderAudioScope(renderArgs); // audio scope in the very back - NOTE: this is the debug audio scope, not the VU meter
renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope
renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts
renderStatsAndLogs(renderArgs); // currently renders nothing
});
renderArgs->_batch = nullptr; // so future users of renderArgs don't try to use our batch
@ -159,27 +158,6 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
qApp->getOverlays().renderHUD(renderArgs);
}
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
// Display stats and log text onscreen
// Determine whether to compute timing details
/*
// Show on-screen msec timer
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
auto canvasSize = qApp->getCanvasSize();
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
QString frameTimer = QString("%1\n").arg((int)(mSecsNow % 1000));
int timerBottom =
(Menu::getInstance()->isOptionChecked(MenuOption::Stats))
? 80 : 20;
drawText(canvasSize.x - 100, canvasSize.y - timerBottom,
0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);
}
*/
}
void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) {
auto geometryCache = DependencyManager::get<GeometryCache>();
static std::once_flag once;
@ -229,13 +207,13 @@ void ApplicationOverlay::buildFramebufferObject() {
auto width = uiSize.x;
auto height = uiSize.y;
if (!_overlayFramebuffer->getDepthStencilBuffer()) {
auto overlayDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(DEPTH_FORMAT, width, height, DEFAULT_SAMPLER));
auto overlayDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(DEPTH_FORMAT, width, height, gpu::Texture::SINGLE_MIP, DEFAULT_SAMPLER));
_overlayFramebuffer->setDepthStencilBuffer(overlayDepthTexture, DEPTH_FORMAT);
}
if (!_overlayFramebuffer->getRenderBuffer(0)) {
const gpu::Sampler OVERLAY_SAMPLER(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP);
auto colorBuffer = gpu::TexturePointer(gpu::Texture::createRenderBuffer(COLOR_FORMAT, width, height, OVERLAY_SAMPLER));
auto colorBuffer = gpu::TexturePointer(gpu::Texture::createRenderBuffer(COLOR_FORMAT, width, height, gpu::Texture::SINGLE_MIP, OVERLAY_SAMPLER));
_overlayFramebuffer->setRenderBuffer(0, colorBuffer);
}
}

View file

@ -62,24 +62,13 @@ AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) {
} \
}
void AvatarInputs::update() {
if (!Menu::getInstance()) {
return;
}
AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking));
AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking));
AI_UPDATE(isHMD, qApp->isHMDMode());
AI_UPDATE_WRITABLE(showAudioTools, Menu::getInstance()->isOptionChecked(MenuOption::AudioTools));
auto audioIO = DependencyManager::get<AudioClient>();
float AvatarInputs::loudnessToAudioLevel(float loudness) {
const float AUDIO_METER_AVERAGING = 0.5;
const float LOG2 = log(2.0f);
const float METER_LOUDNESS_SCALE = 2.8f / 5.0f;
const float LOG2_LOUDNESS_FLOOR = 11.0f;
float audioLevel = 0.0f;
auto audio = DependencyManager::get<AudioClient>();
float loudness = audio->getLastInputLoudness() + 1.0f;
loudness += 1.0f;
_trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness;
@ -93,6 +82,24 @@ void AvatarInputs::update() {
if (audioLevel > 1.0f) {
audioLevel = 1.0;
}
return audioLevel;
}
void AvatarInputs::update() {
if (!Menu::getInstance()) {
return;
}
AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking));
AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking));
AI_UPDATE(isHMD, qApp->isHMDMode());
AI_UPDATE_WRITABLE(showAudioTools, Menu::getInstance()->isOptionChecked(MenuOption::AudioTools));
auto audioIO = DependencyManager::get<AudioClient>();
const float audioLevel = loudnessToAudioLevel(DependencyManager::get<AudioClient>()->getLastInputLoudness());
AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01f);
AI_UPDATE(audioClipping, ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f)));
AI_UPDATE(audioMuted, audioIO->isMuted());

View file

@ -34,6 +34,7 @@ class AvatarInputs : public QQuickItem {
public:
static AvatarInputs* getInstance();
float loudnessToAudioLevel(float loudness);
AvatarInputs(QQuickItem* parent = nullptr);
void update();
bool showAudioTools() const { return _showAudioTools; }

View file

@ -350,11 +350,15 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
QPointF windowPoint(windowPos.x, windowPos.y);
if (event.getButtons() == PointerEvent::NoButtons && event.getType() == PointerEvent::Move) {
// Forward a mouse move event to the Web surface.
if (event.getType() == PointerEvent::Move) {
// Forward a mouse move event to the Web surface so that hover events are generated.
// Must send a mouse move event that matches up with touch move event in order for scroll bars to work.
// Scroll bar dragging is a bit unstable in the tablet (content can jump up and down at times).
// This may be improved in Qt 5.8. Release notes: "Cleaned up touch and mouse event delivery".
QMouseEvent* mouseEvent = new QMouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
return;
}
if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) {

View file

@ -1495,6 +1495,9 @@ void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityC
setAvatarEntityData(identity.avatarEntityData);
identityChanged = true;
}
// flag this avatar as non-stale by updating _averageBytesReceived
const int BOGUS_NUM_BYTES = 1;
_averageBytesReceived.updateAverage(BOGUS_NUM_BYTES);
}
QByteArray AvatarData::identityByteArray() const {

View file

@ -356,15 +356,16 @@ void OpenGLDisplayPlugin::customizeContext() {
cursorData.texture.reset(
gpu::Texture::createStrict(
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
image.width(), image.height(),
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
image.width(), image.height(),
gpu::Texture::MAX_NUM_MIPS,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
cursorData.texture->setSource("cursor texture");
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
cursorData.texture->setUsage(usage.build());
cursorData.texture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
cursorData.texture->assignStoredMip(0, image.byteCount(), image.constBits());
cursorData.texture->autoGenerateMips(-1);
cursorData.texture->setAutoGenerateMips(true);
}
}
}

View file

@ -299,12 +299,13 @@ void HmdDisplayPlugin::internalPresent() {
gpu::Texture::createStrict(
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
image.width(), image.height(),
gpu::Texture::MAX_NUM_MIPS,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
_previewTexture->setSource("HMD Preview Texture");
_previewTexture->setUsage(gpu::Texture::Usage::Builder().withColor().build());
_previewTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
_previewTexture->assignStoredMip(0, image.byteCount(), image.constBits());
_previewTexture->autoGenerateMips(-1);
_previewTexture->setAutoGenerateMips(true);
}
auto viewport = getViewportForSourceSize(uvec2(_previewTexture->getDimensions()));

View file

@ -229,7 +229,7 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
_resource._textures[slot] = resourceTexture;
_stats._RSAmountTextureMemoryBounded += object->size();
_stats._RSAmountTextureMemoryBounded += (int) object->size();
} else {
releaseResourceTexture(slot);

View file

@ -43,7 +43,7 @@ public:
static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES];
protected:
virtual uint32 size() const = 0;
virtual Size size() const = 0;
virtual void generateMips() const = 0;
GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id);
@ -57,7 +57,7 @@ public:
protected:
GLExternalTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id);
void generateMips() const override {}
uint32 size() const override { return 0; }
Size size() const override { return 0; }
};

View file

@ -40,30 +40,59 @@ public:
class GL41Texture : public GLTexture {
using Parent = GLTexture;
static GLuint allocate();
public:
~GL41Texture();
private:
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer);
void generateMips() const override;
uint32 size() const override;
friend class GL41Backend;
const Stamp _storageStamp;
mutable Stamp _contentStamp { 0 };
mutable Stamp _samplerStamp { 0 };
const uint32 _size;
static GLuint allocate(const Texture& texture);
protected:
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
void generateMips() const override;
void copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const;
void copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum format, GLenum type, const void* sourcePointer) const;
virtual void syncSampler() const;
bool isOutdated() const;
void withPreservedTexture(std::function<void()> f) const;
void syncContent() const;
void syncSampler() const;
};
//
// Textures that have fixed allocation sizes and cannot be managed at runtime
//
class GL41FixedAllocationTexture : public GL41Texture {
using Parent = GL41Texture;
friend class GL41Backend;
public:
GL41FixedAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
~GL41FixedAllocationTexture();
protected:
Size size() const override { return _size; }
void allocateStorage() const;
void syncSampler() const override;
const Size _size { 0 };
};
class GL41AttachmentTexture : public GL41FixedAllocationTexture {
using Parent = GL41FixedAllocationTexture;
friend class GL41Backend;
protected:
GL41AttachmentTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
~GL41AttachmentTexture();
};
class GL41StrictResourceTexture : public GL41FixedAllocationTexture {
using Parent = GL41FixedAllocationTexture;
friend class GL41Backend;
protected:
GL41StrictResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
};
class GL41ResourceTexture : public GL41FixedAllocationTexture {
using Parent = GL41FixedAllocationTexture;
friend class GL41Backend;
protected:
GL41ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
~GL41ResourceTexture();
};
protected:
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;

View file

@ -19,20 +19,11 @@ using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl41;
using GL41TexelFormat = GLTexelFormat;
using GL41Texture = GL41Backend::GL41Texture;
GLuint GL41Texture::allocate() {
Backend::incrementTextureGPUCount();
GLuint result;
glGenTextures(1, &result);
return result;
}
GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) {
if (!texturePointer) {
return nullptr;
}
const Texture& texture = *texturePointer;
if (TextureUsageType::EXTERNAL == texture.getUsageType()) {
return Parent::syncGPUObject(texturePointer);
@ -43,90 +34,58 @@ GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) {
return nullptr;
}
// If the object hasn't been created, or the object definition is out of date, drop and re-create
GL41Texture* object = Backend::getGPUObject<GL41Texture>(texture);
if (!object || object->_storageStamp < texture.getStamp()) {
// This automatically any previous texture
object = new GL41Texture(shared_from_this(), texture);
}
if (!object) {
switch (texture.getUsageType()) {
case TextureUsageType::RENDERBUFFER:
object = new GL41AttachmentTexture(shared_from_this(), texture);
break;
// FIXME internalize to GL41Texture 'sync' function
if (object->isOutdated()) {
object->withPreservedTexture([&] {
if (object->_contentStamp <= texture.getDataStamp()) {
// FIXME implement synchronous texture transfer here
object->syncContent();
case TextureUsageType::STRICT_RESOURCE:
qCDebug(gpugllogging) << "Strict texture " << texture.source().c_str();
object = new GL41StrictResourceTexture(shared_from_this(), texture);
break;
case TextureUsageType::RESOURCE: {
qCDebug(gpugllogging) << "variable / Strict texture " << texture.source().c_str();
object = new GL41ResourceTexture(shared_from_this(), texture);
break;
}
if (object->_samplerStamp <= texture.getSamplerStamp()) {
object->syncSampler();
}
});
default:
Q_UNREACHABLE();
}
}
return object;
}
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
: GLTexture(backend, texture, allocate()), _storageStamp { texture.getStamp() }, _size(texture.evalTotalSize()) {
using GL41Texture = GL41Backend::GL41Texture;
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
: GLTexture(backend, texture, allocate(texture)) {
incrementTextureGPUCount();
withPreservedTexture([&] {
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat());
auto numMips = _gpuObject.getNumMipLevels();
for (uint16_t mipLevel = 0; mipLevel < numMips; ++mipLevel) {
// Get the mip level dimensions, accounting for the downgrade level
Vec3u dimensions = _gpuObject.evalMipDimensions(mipLevel);
uint8_t face = 0;
for (GLenum target : getFaceTargets(_target)) {
const Byte* mipData = nullptr;
if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) {
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
mipData = mip->readData();
}
glTexImage2D(target, mipLevel, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, mipData);
(void)CHECK_GL_ERROR();
++face;
}
}
});
}
GL41Texture::~GL41Texture() {
GLuint GL41Texture::allocate(const Texture& texture) {
GLuint result;
glGenTextures(1, &result);
return result;
}
bool GL41Texture::isOutdated() const {
if (_samplerStamp <= _gpuObject.getSamplerStamp()) {
return true;
}
if (TextureUsageType::RESOURCE == _gpuObject.getUsageType() && _contentStamp <= _gpuObject.getDataStamp()) {
return true;
}
return false;
}
void GL41Texture::withPreservedTexture(std::function<void()> f) const {
GLint boundTex = -1;
switch (_target) {
case GL_TEXTURE_2D:
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
break;
case GL_TEXTURE_CUBE_MAP:
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
break;
default:
qFatal("Unsupported texture type");
}
const GLint TRANSFER_TEXTURE_UNIT = 32;
glActiveTexture(GL_TEXTURE0 + TRANSFER_TEXTURE_UNIT);
glBindTexture(_target, _texture);
(void)CHECK_GL_ERROR();
glBindTexture(_target, _texture);
f();
glBindTexture(_target, boundTex);
glBindTexture(_target, 0);
(void)CHECK_GL_ERROR();
}
void GL41Texture::generateMips() const {
withPreservedTexture([&] {
glGenerateMipmap(_target);
@ -134,13 +93,35 @@ void GL41Texture::generateMips() const {
(void)CHECK_GL_ERROR();
}
void GL41Texture::syncContent() const {
// FIXME actually copy the texture data
_contentStamp = _gpuObject.getDataStamp() + 1;
void GL41Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum format, GLenum type, const void* sourcePointer) const {
if (GL_TEXTURE_2D == _target) {
glTexSubImage2D(_target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
} else if (GL_TEXTURE_CUBE_MAP == _target) {
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
glTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
} else {
assert(false);
}
(void)CHECK_GL_ERROR();
}
void GL41Texture::copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const {
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip)) {
return;
}
auto size = _gpuObject.evalMipDimensions(sourceMip);
auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face);
if (mipData) {
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat());
copyMipFaceLinesFromTexture(targetMip, face, size, 0, texelFormat.format, texelFormat.type, mipData->readData());
} else {
qCDebug(gpugllogging) << "Missing mipData level=" << sourceMip << " face=" << (int)face << " for texture " << _gpuObject.source().c_str();
}
}
void GL41Texture::syncSampler() const {
const Sampler& sampler = _gpuObject.getSampler();
const auto& fm = FILTER_MODES[sampler.getFilter()];
glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, fm.minFilter);
glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, fm.magFilter);
@ -158,12 +139,106 @@ void GL41Texture::syncSampler() const {
glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset());
glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
_samplerStamp = _gpuObject.getSamplerStamp() + 1;
}
uint32 GL41Texture::size() const {
return _size;
using GL41FixedAllocationTexture = GL41Backend::GL41FixedAllocationTexture;
GL41FixedAllocationTexture::GL41FixedAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41Texture(backend, texture), _size(texture.evalTotalSize()) {
withPreservedTexture([&] {
allocateStorage();
syncSampler();
});
}
GL41FixedAllocationTexture::~GL41FixedAllocationTexture() {
}
void GL41FixedAllocationTexture::allocateStorage() const {
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
const auto numMips = _gpuObject.getNumMips();
// glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
for (GLint level = 0; level < numMips; level++) {
Vec3u dimensions = _gpuObject.evalMipDimensions(level);
for (GLenum target : getFaceTargets(_target)) {
glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, nullptr);
}
}
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, numMips - 1);
}
void GL41FixedAllocationTexture::syncSampler() const {
Parent::syncSampler();
const Sampler& sampler = _gpuObject.getSampler();
auto baseMip = std::max<uint16_t>(sampler.getMipOffset(), sampler.getMinMip());
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, baseMip);
glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.0f : sampler.getMaxMip()));
}
// Renderbuffer attachment textures
using GL41AttachmentTexture = GL41Backend::GL41AttachmentTexture;
GL41AttachmentTexture::GL41AttachmentTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) {
Backend::updateTextureGPUFramebufferMemoryUsage(0, size());
}
GL41AttachmentTexture::~GL41AttachmentTexture() {
Backend::updateTextureGPUFramebufferMemoryUsage(size(), 0);
}
// Strict resource textures
using GL41StrictResourceTexture = GL41Backend::GL41StrictResourceTexture;
GL41StrictResourceTexture::GL41StrictResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) {
withPreservedTexture([&] {
auto mipLevels = _gpuObject.getNumMips();
for (uint16_t sourceMip = 0; sourceMip < mipLevels; sourceMip++) {
uint16_t targetMip = sourceMip;
size_t maxFace = GLTexture::getFaceCount(_target);
for (uint8_t face = 0; face < maxFace; face++) {
copyMipFaceFromTexture(sourceMip, targetMip, face);
}
}
});
if (texture.isAutogenerateMips()) {
generateMips();
}
}
// resource textures
using GL41ResourceTexture = GL41Backend::GL41ResourceTexture;
GL41ResourceTexture::GL41ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) {
Backend::updateTextureGPUMemoryUsage(0, size());
withPreservedTexture([&] {
auto mipLevels = _gpuObject.getNumMips();
for (uint16_t sourceMip = 0; sourceMip < mipLevels; sourceMip++) {
uint16_t targetMip = sourceMip;
size_t maxFace = GLTexture::getFaceCount(_target);
for (uint8_t face = 0; face < maxFace; face++) {
copyMipFaceFromTexture(sourceMip, targetMip, face);
}
}
});
if (texture.isAutogenerateMips()) {
generateMips();
}
}
GL41ResourceTexture::~GL41ResourceTexture() {
Backend::updateTextureGPUMemoryUsage(size(), 0);
}

View file

@ -58,10 +58,10 @@ public:
~GL45FixedAllocationTexture();
protected:
uint32 size() const override { return _size; }
Size size() const override { return _size; }
void allocateStorage() const;
void syncSampler() const override;
const uint32 _size { 0 };
const Size _size { 0 };
};
class GL45AttachmentTexture : public GL45FixedAllocationTexture {
@ -173,7 +173,7 @@ public:
bool canDemote() const { return _allocatedMip < _maxAllocatedMip; }
bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; }
void executeNextTransfer(const TexturePointer& currentTexture);
uint32 size() const override { return _size; }
Size size() const override { return _size; }
virtual void populateTransferQueue() = 0;
virtual void promote() = 0;
virtual void demote() = 0;
@ -188,7 +188,7 @@ public:
// The highest (lowest resolution) mip that we will support, relative to the number
// of mips in the gpu::Texture object
uint16 _maxAllocatedMip { 0 };
uint32 _size { 0 };
Size _size { 0 };
// Contains a series of lambdas that when executed will transfer data to the GPU, modify
// the _populatedMip and update the sampler in order to fully populate the allocated texture
// until _populatedMip == _allocatedMip

View file

@ -18,7 +18,6 @@
#include <glm/gtx/component_wise.hpp>
#include <QtCore/QDebug>
#include <QtCore/QThread>
#include <NumericalConstants.h>
#include "../gl/GLTexelFormat.h"
@ -167,8 +166,10 @@ void GL45Texture::syncSampler() const {
glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]);
glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]);
glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]);
glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip());
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
}
@ -186,10 +187,12 @@ GL45FixedAllocationTexture::~GL45FixedAllocationTexture() {
void GL45FixedAllocationTexture::allocateStorage() const {
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
const auto dimensions = _gpuObject.getDimensions();
const auto mips = _gpuObject.getNumMipLevels();
const auto mips = _gpuObject.getNumMips();
glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, mips - 1);
}
void GL45FixedAllocationTexture::syncSampler() const {
@ -216,7 +219,7 @@ GL45AttachmentTexture::~GL45AttachmentTexture() {
using GL45StrictResourceTexture = GL45Backend::GL45StrictResourceTexture;
GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45FixedAllocationTexture(backend, texture) {
auto mipLevels = _gpuObject.getNumMipLevels();
auto mipLevels = _gpuObject.getNumMips();
for (uint16_t sourceMip = 0; sourceMip < mipLevels; ++sourceMip) {
uint16_t targetMip = sourceMip;
size_t maxFace = GLTexture::getFaceCount(_target);

View file

@ -441,7 +441,7 @@ void GL45VariableAllocationTexture::executeNextTransfer(const TexturePointer& cu
using GL45ResourceTexture = GL45Backend::GL45ResourceTexture;
GL45ResourceTexture::GL45ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45VariableAllocationTexture(backend, texture) {
auto mipLevels = texture.evalNumMips();
auto mipLevels = texture.getNumMips();
_allocatedMip = mipLevels;
uvec3 mipDimensions;
for (uint16_t mip = 0; mip < mipLevels; ++mip) {
@ -463,10 +463,10 @@ void GL45ResourceTexture::allocateStorage(uint16 allocatedMip) {
_allocatedMip = allocatedMip;
const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
const auto dimensions = _gpuObject.evalMipDimensions(_allocatedMip);
const auto totalMips = _gpuObject.getNumMipLevels();
const auto totalMips = _gpuObject.getNumMips();
const auto mips = totalMips - _allocatedMip;
glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y);
auto mipLevels = _gpuObject.getNumMipLevels();
auto mipLevels = _gpuObject.getNumMips();
_size = 0;
for (uint16_t mip = _allocatedMip; mip < mipLevels; ++mip) {
_size += _gpuObject.evalMipSize(mip);
@ -476,7 +476,7 @@ void GL45ResourceTexture::allocateStorage(uint16 allocatedMip) {
}
void GL45ResourceTexture::copyMipsFromTexture() {
auto mipLevels = _gpuObject.getNumMipLevels();
auto mipLevels = _gpuObject.getNumMips();
size_t maxFace = GLTexture::getFaceCount(_target);
for (uint16_t sourceMip = _populatedMip; sourceMip < mipLevels; ++sourceMip) {
uint16_t targetMip = sourceMip - _allocatedMip;
@ -495,13 +495,13 @@ void GL45ResourceTexture::promote() {
PROFILE_RANGE(render_gpu_gl, __FUNCTION__);
Q_ASSERT(_allocatedMip > 0);
GLuint oldId = _id;
uint32_t oldSize = _size;
auto oldSize = _size;
// create new texture
const_cast<GLuint&>(_id) = allocate(_gpuObject);
uint16_t oldAllocatedMip = _allocatedMip;
// allocate storage for new level
allocateStorage(_allocatedMip - std::min<uint16_t>(_allocatedMip, 2));
uint16_t mips = _gpuObject.getNumMipLevels();
uint16_t mips = _gpuObject.getNumMips();
// copy pre-existing mips
for (uint16_t mip = _populatedMip; mip < mips; ++mip) {
auto mipDimensions = _gpuObject.evalMipDimensions(mip);
@ -534,7 +534,7 @@ void GL45ResourceTexture::demote() {
const_cast<GLuint&>(_id) = allocate(_gpuObject);
allocateStorage(_allocatedMip + 1);
_populatedMip = std::max(_populatedMip, _allocatedMip);
uint16_t mips = _gpuObject.getNumMipLevels();
uint16_t mips = _gpuObject.getNumMips();
// copy pre-existing mips
for (uint16_t mip = _populatedMip; mip < mips; ++mip) {
auto mipDimensions = _gpuObject.evalMipDimensions(mip);

View file

@ -265,7 +265,7 @@ void Context::incrementBufferGPUCount() {
auto total = ++_bufferGPUCount;
if (total > max.load()) {
max = total;
qCDebug(gpulogging) << "New max GPU buffers " << total;
// qCDebug(gpulogging) << "New max GPU buffers " << total;
}
}
void Context::decrementBufferGPUCount() {
@ -299,7 +299,7 @@ void Context::incrementTextureGPUCount() {
auto total = ++_textureGPUCount;
if (total > max.load()) {
max = total;
qCDebug(gpulogging) << "New max GPU textures " << total;
// qCDebug(gpulogging) << "New max GPU textures " << total;
}
}
void Context::decrementTextureGPUCount() {
@ -311,7 +311,7 @@ void Context::incrementTextureGPUSparseCount() {
auto total = ++_textureGPUSparseCount;
if (total > max.load()) {
max = total;
qCDebug(gpulogging) << "New max GPU textures " << total;
// qCDebug(gpulogging) << "New max GPU textures " << total;
}
}
void Context::decrementTextureGPUSparseCount() {
@ -378,7 +378,7 @@ void Context::incrementTextureGPUTransferCount() {
auto total = ++_textureGPUTransferCount;
if (total > max.load()) {
max = total;
qCDebug(gpulogging) << "New max GPU textures transfers" << total;
// qCDebug(gpulogging) << "New max GPU textures transfers" << total;
}
}

View file

@ -32,7 +32,7 @@ Framebuffer* Framebuffer::create(const std::string& name) {
Framebuffer* Framebuffer::create(const std::string& name, const Format& colorBufferFormat, uint16 width, uint16 height) {
auto framebuffer = Framebuffer::create(name);
auto colorTexture = TexturePointer(Texture::createRenderBuffer(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
auto colorTexture = TexturePointer(Texture::createRenderBuffer(colorBufferFormat, width, height, Texture::SINGLE_MIP, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
colorTexture->setSource("Framebuffer::colorTexture");
framebuffer->setRenderBuffer(0, colorTexture);
@ -43,8 +43,8 @@ Framebuffer* Framebuffer::create(const std::string& name, const Format& colorBuf
Framebuffer* Framebuffer::create(const std::string& name, const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height) {
auto framebuffer = Framebuffer::create(name);
auto colorTexture = TexturePointer(Texture::createRenderBuffer(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
auto depthTexture = TexturePointer(Texture::createRenderBuffer(depthStencilBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
auto colorTexture = TexturePointer(Texture::createRenderBuffer(colorBufferFormat, width, height, Texture::SINGLE_MIP, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
auto depthTexture = TexturePointer(Texture::createRenderBuffer(depthStencilBufferFormat, width, height, Texture::SINGLE_MIP, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
framebuffer->setRenderBuffer(0, colorTexture);
framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat);

View file

@ -149,8 +149,14 @@ PixelsPointer MemoryStorage::getMipFace(uint16 level, uint8 face) const {
return PixelsPointer();
}
Size MemoryStorage::getMipFaceSize(uint16 level, uint8 face) const {
return getMipFace(level, face)->getSize();
PixelsPointer mipFace = getMipFace(level, face);
if (mipFace) {
return mipFace->getSize();
} else {
return 0;
}
}
bool MemoryStorage::isMipAvailable(uint16 level, uint8 face) const {
@ -209,44 +215,43 @@ void Texture::MemoryStorage::assignMipFaceData(uint16 level, uint8 face, const s
Texture* Texture::createExternal(const ExternalRecycler& recycler, const Sampler& sampler) {
Texture* tex = new Texture(TextureUsageType::EXTERNAL);
tex->_type = TEX_2D;
tex->_maxMip = 0;
tex->_maxMipLevel = 0;
tex->_sampler = sampler;
tex->setExternalRecycler(recycler);
return tex;
}
Texture* Texture::createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) {
return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, 0, sampler);
Texture* Texture::createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::RENDERBUFFER, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
}
Texture* Texture::create1D(const Element& texelFormat, uint16 width, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_1D, texelFormat, width, 1, 1, 1, 0, sampler);
Texture* Texture::create1D(const Element& texelFormat, uint16 width, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_1D, texelFormat, width, 1, 1, 1, 0, numMips, sampler);
}
Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, sampler);
Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
}
Texture* Texture::createStrict(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) {
return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, sampler);
Texture* Texture::createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::STRICT_RESOURCE, TEX_2D, texelFormat, width, height, 1, 1, 0, numMips, sampler);
}
Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_3D, texelFormat, width, height, depth, 1, 0, sampler);
Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_3D, texelFormat, width, height, depth, 1, 0, numMips, sampler);
}
Texture* Texture::createCube(const Element& texelFormat, uint16 width, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_CUBE, texelFormat, width, width, 1, 1, 0, sampler);
Texture* Texture::createCube(const Element& texelFormat, uint16 width, uint16 numMips, const Sampler& sampler) {
return create(TextureUsageType::RESOURCE, TEX_CUBE, texelFormat, width, width, 1, 1, 0, numMips, sampler);
}
Texture* Texture::create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler)
Texture* Texture::create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips, const Sampler& sampler)
{
Texture* tex = new Texture(usageType);
tex->_storage.reset(new MemoryStorage());
tex->_type = type;
tex->_storage->assignTexture(tex);
tex->_maxMip = 0;
tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices);
tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices, numMips);
tex->_sampler = sampler;
@ -278,7 +283,7 @@ Texture::~Texture() {
}
}
Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) {
Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips) {
if (width && height && depth && numSamples) {
bool changed = false;
@ -313,9 +318,19 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt
_depth = depth;
changed = true;
}
if ((_maxMipLevel + 1) != numMips) {
_maxMipLevel = safeNumMips(numMips) - 1;
changed = true;
}
if (texelFormat != _texelFormat) {
_texelFormat = texelFormat;
changed = true;
}
// Evaluate the new size with the new format
uint32_t size = NUM_FACES_PER_TYPE[_type] *_width * _height * _depth * _numSamples * texelFormat.getSize();
Size size = NUM_FACES_PER_TYPE[_type] * _height * _depth * evalPaddedSize(_numSamples * _width * _texelFormat.getSize());
// If size change then we need to reset
if (changed || (size != getSize())) {
@ -324,12 +339,6 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt
_stamp++;
}
// TexelFormat might have change, but it's mostly interpretation
if (texelFormat != _texelFormat) {
_texelFormat = texelFormat;
_stamp++;
}
// Here the Texture has been fully defined from the gpu point of view (size and format)
_defined = true;
} else {
@ -339,23 +348,6 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt
return _size;
}
Texture::Size Texture::resize1D(uint16 width, uint16 numSamples) {
return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 0);
}
Texture::Size Texture::resize2D(uint16 width, uint16 height, uint16 numSamples) {
return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 0);
}
Texture::Size Texture::resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples) {
return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 0);
}
Texture::Size Texture::resizeCube(uint16 width, uint16 numSamples) {
return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 0);
}
Texture::Size Texture::reformat(const Element& texelFormat) {
return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), _numSlices);
}
bool Texture::isColorRenderTarget() const {
return (_texelFormat.getSemantic() == gpu::RGBA);
}
@ -364,7 +356,7 @@ bool Texture::isDepthStencilRenderTarget() const {
return (_texelFormat.getSemantic() == gpu::DEPTH) || (_texelFormat.getSemantic() == gpu::DEPTH_STENCIL);
}
uint16 Texture::evalDimNumMips(uint16 size) {
uint16 Texture::evalDimMaxNumMips(uint16 size) {
double largerDim = size;
double val = log(largerDim)/log(2.0);
return 1 + (uint16) val;
@ -372,7 +364,7 @@ uint16 Texture::evalDimNumMips(uint16 size) {
static const double LOG_2 = log(2.0);
uint16 Texture::evalNumMips(const Vec3u& dimensions) {
uint16 Texture::evalMaxNumMips(const Vec3u& dimensions) {
double largerDim = glm::compMax(dimensions);
double val = log(largerDim) / LOG_2;
return 1 + (uint16)val;
@ -380,8 +372,34 @@ uint16 Texture::evalNumMips(const Vec3u& dimensions) {
// The number mips that the texture could have if all existed
// = log2(max(width, height, depth))
uint16 Texture::evalNumMips() const {
return evalNumMips({ _width, _height, _depth });
uint16 Texture::evalMaxNumMips() const {
return evalMaxNumMips({ _width, _height, _depth });
}
// Check a num of mips requested against the maximum possible specified
// if passing -1 then answer the max
// simply does (askedNumMips == 0 ? maxNumMips : (numstd::min(askedNumMips, maxNumMips))
uint16 Texture::safeNumMips(uint16 askedNumMips, uint16 maxNumMips) {
if (askedNumMips > 0) {
return std::min(askedNumMips, maxNumMips);
} else {
return maxNumMips;
}
}
// Same but applied to this texture's num max mips from evalNumMips()
uint16 Texture::safeNumMips(uint16 askedNumMips) const {
return safeNumMips(askedNumMips, evalMaxNumMips());
}
Size Texture::evalTotalSize(uint16 startingMip) const {
Size size = 0;
uint16 minMipLevel = std::max(getMinMip(), startingMip);
uint16 maxMipLevel = getMaxMip();
for (uint16 level = minMipLevel; level <= maxMipLevel; level++) {
size += evalMipSize(level);
}
return size * getNumSlices();
}
void Texture::setStoredMipFormat(const Element& format) {
@ -408,7 +426,7 @@ void Texture::assignStoredMip(uint16 level, storage::StoragePointer& storage) {
if (_autoGenerateMips) {
return;
}
if (level >= evalNumMips()) {
if (level >= getNumMips()) {
return;
}
}
@ -418,7 +436,6 @@ void Texture::assignStoredMip(uint16 level, storage::StoragePointer& storage) {
auto size = storage->size();
if (storage->size() == expectedSize) {
_storage->assignMipData(level, storage);
_maxMip = std::max(_maxMip, level);
_stamp++;
} else if (size > expectedSize) {
// NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images
@ -426,7 +443,6 @@ void Texture::assignStoredMip(uint16 level, storage::StoragePointer& storage) {
// We should probably consider something a bit more smart to get the correct result but for now (UI elements)
// it seems to work...
_storage->assignMipData(level, storage);
_maxMip = std::max(_maxMip, level);
_stamp++;
}
}
@ -437,7 +453,7 @@ void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePoin
if (_autoGenerateMips) {
return;
}
if (level >= evalNumMips()) {
if (level >= getNumMips()) {
return;
}
}
@ -447,7 +463,6 @@ void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePoin
auto size = storage->size();
if (size == expectedSize) {
_storage->assignMipFaceData(level, face, storage);
_maxMip = std::max(_maxMip, level);
_stamp++;
} else if (size > expectedSize) {
// NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images
@ -455,71 +470,36 @@ void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePoin
// We should probably consider something a bit more smart to get the correct result but for now (UI elements)
// it seems to work...
_storage->assignMipFaceData(level, face, storage);
_maxMip = std::max(_maxMip, level);
_stamp++;
}
}
uint16 Texture::autoGenerateMips(uint16 maxMip) {
void Texture::setAutoGenerateMips(bool enable) {
bool changed = false;
if (!_autoGenerateMips) {
changed = true;
_autoGenerateMips = true;
}
auto newMaxMip = std::min((uint16)(evalNumMips() - 1), maxMip);
if (newMaxMip != _maxMip) {
changed = true;
_maxMip = newMaxMip;;
}
if (changed) {
_stamp++;
}
return _maxMip;
}
uint16 Texture::getStoredMipWidth(uint16 level) const {
if (!isStoredMipFaceAvailable(level)) {
return 0;
Size Texture::getStoredMipSize(uint16 level) const {
PixelsPointer mipFace = accessStoredMipFace(level);
Size size = 0;
if (mipFace && mipFace->getSize()) {
for (int face = 0; face < getNumFaces(); face++) {
size += getStoredMipFaceSize(level, face);
}
}
return evalMipWidth(level);
return size;
}
uint16 Texture::getStoredMipHeight(uint16 level) const {
if (!isStoredMipFaceAvailable(level)) {
return 0;
}
return evalMipHeight(level);
}
uint16 Texture::getStoredMipDepth(uint16 level) const {
if (!isStoredMipFaceAvailable(level)) {
return 0;
}
return evalMipDepth(level);
}
uint32 Texture::getStoredMipNumTexels(uint16 level) const {
if (!isStoredMipFaceAvailable(level)) {
return 0;
}
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
}
uint32 Texture::getStoredMipSize(uint16 level) const {
if (!isStoredMipFaceAvailable(level)) {
return 0;
}
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
}
gpu::Resource::Size Texture::getStoredSize() const {
auto size = 0;
for (int level = 0; level < evalNumMips(); ++level) {
Size Texture::getStoredSize() const {
Size size = 0;
for (int level = 0; level < getNumMips(); level++) {
size += getStoredMipSize(level);
}
return size;
@ -937,7 +917,7 @@ bool TextureSource::isDefined() const {
bool Texture::setMinMip(uint16 newMinMip) {
uint16 oldMinMip = _minMip;
_minMip = std::min(std::max(_minMip, newMinMip), _maxMip);
_minMip = std::min(std::max(_minMip, newMinMip), getMaxMip());
return oldMinMip != _minMip;
}

View file

@ -232,9 +232,7 @@ public:
bool operator!=(const Usage& usage) { return (_flags != usage._flags); }
};
using PixelsPointer = storage::StoragePointer;
enum Type {
enum Type : uint8 {
TEX_1D = 0,
TEX_2D,
TEX_3D,
@ -255,7 +253,13 @@ public:
NUM_CUBE_FACES, // Not a valid vace index
};
// Lines of pixels are padded to be a multiple of "PACKING_SIZE" which is 4 bytes
static const uint32 PACKING_SIZE = 4;
static uint8 evalPaddingNumBytes(Size byteSize) { return (uint8) (3 - (byteSize + 3) % PACKING_SIZE); }
static Size evalPaddedSize(Size byteSize) { return byteSize + (Size) evalPaddingNumBytes(byteSize); }
using PixelsPointer = storage::StoragePointer;
class Storage {
public:
Storage() {}
@ -322,14 +326,19 @@ public:
friend class Texture;
};
static Texture* create1D(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler());
static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler());
static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler = Sampler());
static Texture* createCube(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler());
static Texture* createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler());
static Texture* createStrict(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler());
static const uint16 MAX_NUM_MIPS = 0;
static const uint16 SINGLE_MIP = 1;
static Texture* create1D(const Element& texelFormat, uint16 width, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static Texture* createCube(const Element& texelFormat, uint16 width, uint16 numMips = 1, const Sampler& sampler = Sampler());
static Texture* createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static Texture* createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
static Texture* createExternal(const ExternalRecycler& recycler, const Sampler& sampler = Sampler());
// After the texture has been created, it should be defined
bool isDefined() const { return _defined; }
Texture(TextureUsageType usageType);
Texture(const Texture& buf); // deep copy of the sysmem texture
Texture& operator=(const Texture& buf); // deep copy of the sysmem texture
@ -339,20 +348,9 @@ public:
Stamp getDataStamp() const { return _storage->getStamp(); }
// The theoretical size in bytes of data stored in the texture
// For the master (level) first level of mip
Size getSize() const override { return _size; }
// The actual size in bytes of data stored in the texture
Size getStoredSize() const;
// Resize, unless auto mips mode would destroy all the sub mips
Size resize1D(uint16 width, uint16 numSamples);
Size resize2D(uint16 width, uint16 height, uint16 numSamples);
Size resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples);
Size resizeCube(uint16 width, uint16 numSamples);
// Reformat, unless auto mips mode would destroy all the sub mips
Size reformat(const Element& texelFormat);
// Size and format
Type getType() const { return _type; }
TextureUsageType getUsageType() const { return _usageType; }
@ -361,23 +359,18 @@ public:
bool isDepthStencilRenderTarget() const;
const Element& getTexelFormat() const { return _texelFormat; }
bool hasBorder() const { return false; }
Vec3u getDimensions() const { return Vec3u(_width, _height, _depth); }
uint16 getWidth() const { return _width; }
uint16 getHeight() const { return _height; }
uint16 getDepth() const { return _depth; }
uint32 getRowPitch() const { return getWidth() * getTexelFormat().getSize(); }
// The number of faces is mostly used for cube map, and maybe for stereo ? otherwise it's 1
// For cube maps, this means the pixels of the different faces are supposed to be packed back to back in a mip
// as if the height was NUM_FACES time bigger.
static uint8 NUM_FACES_PER_TYPE[NUM_TYPES];
uint8 getNumFaces() const { return NUM_FACES_PER_TYPE[getType()]; }
uint32 getNumTexels() const { return _width * _height * _depth * getNumFaces(); }
// The texture is an array if the _numSlices is not 0.
// otherwise, if _numSLices is 0, then the texture is NOT an array
// The number of slices returned is 1 at the minimum (if not an array) or the actual _numSlices.
@ -385,79 +378,74 @@ public:
uint16 getNumSlices() const { return (isArray() ? _numSlices : 1); }
uint16 getNumSamples() const { return _numSamples; }
// NumSamples can only have certain values based on the hw
static uint16 evalNumSamplesUsed(uint16 numSamplesTried);
// max mip is in the range [ 0 if no sub mips, log2(max(width, height, depth))]
// It is defined at creation time (immutable)
uint16 getMaxMip() const { return _maxMipLevel; }
uint16 getNumMips() const { return _maxMipLevel + 1; }
// Mips size evaluation
// The number mips that a dimension could haves
// = 1 + log2(size)
static uint16 evalDimNumMips(uint16 size);
static uint16 evalDimMaxNumMips(uint16 size);
// The number mips that the texture could have if all existed
// = 1 + log2(max(width, height, depth))
uint16 evalNumMips() const;
uint16 evalMaxNumMips() const;
static uint16 evalMaxNumMips(const Vec3u& dimensions);
static uint16 evalNumMips(const Vec3u& dimensions);
// Check a num of mips requested against the maximum possible specified
// if passing -1 then answer the max
// simply does (askedNumMips == -1 ? maxMips : (numstd::min(askedNumMips, max))
static uint16 safeNumMips(uint16 askedNumMips, uint16 maxMips);
// Same but applied to this texture's num max mips from evalNumMips()
uint16 safeNumMips(uint16 askedNumMips) const;
// Eval the size that the mips level SHOULD have
// not the one stored in the Texture
static const uint MIN_DIMENSION = 1;
Vec3u evalMipDimensions(uint16 level) const;
uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); }
uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); }
uint16 evalMipDepth(uint16 level) const { return std::max(_depth >> level, 1); }
// The size of a face is a multiple of the padded line = (width * texelFormat_size + alignment padding)
Size evalMipLineSize(uint16 level) const { return evalPaddedSize(evalMipWidth(level) * getTexelFormat().getSize()); }
// Size for each face of a mip at a particular level
uint32 evalMipFaceNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); }
uint32 evalMipFaceSize(uint16 level) const { return evalMipFaceNumTexels(level) * getTexelFormat().getSize(); }
Size evalMipFaceSize(uint16 level) const { return evalMipLineSize(level) * evalMipHeight(level) * evalMipDepth(level); }
// Total size for the mip
uint32 evalMipNumTexels(uint16 level) const { return evalMipFaceNumTexels(level) * getNumFaces(); }
uint32 evalMipSize(uint16 level) const { return evalMipNumTexels(level) * getTexelFormat().getSize(); }
Size evalMipSize(uint16 level) const { return evalMipFaceSize(level) * getNumFaces(); }
uint32 evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); }
uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); }
// Total size for all the mips of the texture
Size evalTotalSize(uint16 startingMip = 0) const;
uint32 evalTotalSize(uint16 startingMip = 0) const {
uint32 size = 0;
uint16 minMipLevel = std::max(getMinMip(), startingMip);
uint16 maxMipLevel = getMaxMip();
for (uint16 l = minMipLevel; l <= maxMipLevel; l++) {
size += evalMipSize(l);
}
return size * getNumSlices();
}
// max mip is in the range [ 0 if no sub mips, log2(max(width, height, depth))]
// if autoGenerateMip is on => will provide the maxMIp level specified
// else provide the deepest mip level provided through assignMip
uint16 getMaxMip() const { return _maxMip; }
uint16 getMinMip() const { return _minMip; }
uint16 getNumMipLevels() const { return _maxMip + 1; }
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
// Compute the theorical size of the texture elements storage depending on the specified format
Size evalStoredMipLineSize(uint16 level, const Element& format) const { return evalPaddedSize(evalMipWidth(level) * format.getSize()); }
Size evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); }
Size evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); }
// For convenience assign a source name
const std::string& source() const { return _source; }
void setSource(const std::string& source) { _source = source; }
// Potentially change the minimum mip (mostly for debugging purpose)
bool setMinMip(uint16 newMinMip);
bool incremementMinMip(uint16 count = 1);
uint16 getMinMip() const { return _minMip; }
uint16 usedMipLevels() const { return (getNumMips() - _minMip); }
// Generate the mips automatically
// But the sysmem version is not available
// Generate the sub mips automatically for the texture
// If the storage version is not available (from CPU memory)
// Only works for the standard formats
// Specify the maximum Mip level available
// 0 is the default one
// 1 is the first level
// ...
// nbMips - 1 is the last mip level
//
// If -1 then all the mips are generated
//
// Return the totalnumber of mips that will be available
uint16 autoGenerateMips(uint16 maxMip);
void setAutoGenerateMips(bool enable);
bool isAutogenerateMips() const { return _autoGenerateMips; }
// Managing Storage and mips
@ -471,30 +459,22 @@ public:
// in case autoGen is on, this doesn't allocate
// Explicitely assign mip data for a certain level
// If Bytes is NULL then simply allocate the space so mip sysmem can be accessed
void assignStoredMip(uint16 level, Size size, const Byte* bytes);
void assignStoredMipFace(uint16 level, uint8 face, Size size, const Byte* bytes);
void assignStoredMip(uint16 level, storage::StoragePointer& storage);
void assignStoredMipFace(uint16 level, uint8 face, storage::StoragePointer& storage);
// Access the the sub mips
bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); }
// Access the stored mips and faces
const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); }
bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); }
Size getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); }
Size getStoredMipSize(uint16 level) const;
Size getStoredSize() const;
void setStorage(std::unique_ptr<Storage>& newStorage);
void setKtxBacking(const std::string& filename);
// access sizes for the stored mips
uint16 getStoredMipWidth(uint16 level) const;
uint16 getStoredMipHeight(uint16 level) const;
uint16 getStoredMipDepth(uint16 level) const;
uint32 getStoredMipNumTexels(uint16 level) const;
uint32 getStoredMipSize(uint16 level) const;
bool isDefined() const { return _defined; }
// Usage is a a set of flags providing Semantic about the usage of the Texture.
void setUsage(const Usage& usage) { _usage = usage; }
Usage getUsage() const { return _usage; }
@ -520,7 +500,7 @@ public:
ExternalUpdates getUpdates() const;
// Textures can be serialized directly to ktx data file, here is how
// Textures can be serialized directly to ktx data file, here is how
static ktx::KTXUniquePointer serialize(const Texture& texture);
static Texture* unserialize(const std::string& ktxFile, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc());
static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
@ -545,7 +525,7 @@ protected:
Sampler _sampler;
Stamp _samplerStamp { 0 };
uint32 _size { 0 };
Size _size { 0 };
Element _texelFormat;
uint16 _width { 1 };
@ -553,9 +533,14 @@ protected:
uint16 _depth { 1 };
uint16 _numSamples { 1 };
uint16 _numSlices { 0 }; // if _numSlices is 0, the texture is not an "Array", the getNumSlices reported is 1
uint16 _maxMip { 0 };
// if _numSlices is 0, the texture is not an "Array", the getNumSlices reported is 1
uint16 _numSlices { 0 };
// valid _maxMipLevel is in the range [ 0 if no sub mips, log2(max(width, height, depth) ]
// The num of mips returned is _maxMipLevel + 1
uint16 _maxMipLevel { 0 };
uint16 _minMip { 0 };
Type _type { TEX_1D };
@ -567,9 +552,9 @@ protected:
bool _isIrradianceValid = false;
bool _defined = false;
static Texture* create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler);
static Texture* create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips, const Sampler& sampler);
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips);
};
typedef std::shared_ptr<Texture> TexturePointer;

View file

@ -128,7 +128,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
}
// Number level of mips coming
header.numberOfMipmapLevels = texture.getNumMipLevels();
header.numberOfMipmapLevels = texture.getNumMips();
ktx::Images images;
for (uint32_t level = 0; level < header.numberOfMipmapLevels; level++) {
@ -224,6 +224,7 @@ Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usage
header.getPixelDepth(),
1, // num Samples
header.getNumberOfSlices(),
header.getNumberOfLevels(),
(isGPUKTXPayload ? gpuktxKeyValue._samplerDesc : sampler));
tex->setUsage((isGPUKTXPayload ? gpuktxKeyValue._usage : usage));

View file

@ -148,7 +148,7 @@ void Light::setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset) {
void Light::setAmbientMap(gpu::TexturePointer ambientMap) {
_ambientMap = ambientMap;
if (ambientMap) {
setAmbientMapNumMips(_ambientMap->evalNumMips());
setAmbientMapNumMips(_ambientMap->getNumMips());
} else {
setAmbientMapNumMips(0);
}

View file

@ -210,7 +210,7 @@ const QImage& image, bool isLinear, bool doCompress) {
void generateMips(gpu::Texture* texture, QImage& image, bool fastResize) {
#if CPU_MIPMAPS
PROFILE_RANGE(resource_parse, "generateMips");
auto numMips = texture->evalNumMips();
auto numMips = texture->getNumMips();
for (uint16 level = 1; level < numMips; ++level) {
QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level));
if (fastResize) {
@ -230,7 +230,7 @@ void generateMips(gpu::Texture* texture, QImage& image, bool fastResize) {
void generateFaceMips(gpu::Texture* texture, QImage& image, uint8 face) {
#if CPU_MIPMAPS
PROFILE_RANGE(resource_parse, "generateFaceMips");
auto numMips = texture->evalNumMips();
auto numMips = texture->getNumMips();
for (uint16 level = 1; level < numMips; ++level) {
QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level));
QImage mipImage = image.scaled(mipSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
@ -255,9 +255,9 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
if (isStrict) {
theTexture = (gpu::Texture::createStrict(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture = (gpu::Texture::createStrict(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
} else {
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
}
theTexture->setSource(srcImageName);
auto usage = gpu::Texture::Usage::Builder().withColor();
@ -317,7 +317,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src
gpu::Element formatMip = gpu::Element::COLOR_BGRA_32;
gpu::Element formatGPU = gpu::Element::COLOR_RGBA_32;
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->setStoredMipFormat(formatMip);
theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
@ -345,8 +345,8 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
PROFILE_RANGE(resource_parse, "createNormalTextureFromBumpImage");
QImage image = processSourceImage(srcImage, false);
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
if (image.format() != QImage::Format_Grayscale8) {
image = image.convertToFormat(QImage::Format_Grayscale8);
}
// PR 5540 by AlessandroSigna integrated here as a specialized TextureLoader for bumpmaps
@ -395,7 +395,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
glm::normalize(v);
// convert to rgb from the value obtained computing the filter
QRgb qRgbValue = qRgba(mapComponent(v.x), mapComponent(v.y), mapComponent(v.z), 1.0);
QRgb qRgbValue = qRgba(mapComponent(v.z), mapComponent(v.y), mapComponent(v.x), 1.0);
result.setPixel(i, j, qRgbValue);
}
}
@ -407,7 +407,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
gpu::Element formatGPU = gpu::Element::COLOR_RGBA_32;
theTexture = (gpu::Texture::create2D(formatGPU, result.width(), result.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture = (gpu::Texture::create2D(formatGPU, result.width(), result.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->setStoredMipFormat(formatMip);
theTexture->assignStoredMip(0, result.byteCount(), result.constBits());
@ -443,7 +443,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
#endif
gpu::Element formatMip = gpu::Element::COLOR_R_8;
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->setStoredMipFormat(formatMip);
theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
@ -483,7 +483,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
#endif
gpu::Element formatMip = gpu::Element::COLOR_R_8;
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->setStoredMipFormat(formatMip);
theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
@ -520,7 +520,7 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag
#endif
gpu::Element formatMip = gpu::Element::COLOR_R_8;
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->setStoredMipFormat(formatMip);
theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
@ -836,7 +836,7 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
// If the 6 faces have been created go on and define the true Texture
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
theTexture->setSource(srcImageName);
theTexture->setStoredMipFormat(formatMip);
int f = 0;
@ -848,11 +848,6 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
f++;
}
if (generateMips) {
PROFILE_RANGE(resource_parse, "generateMips");
theTexture->autoGenerateMips(-1);
}
// Generate irradiance while we are at it
if (generateIrradiance) {
PROFILE_RANGE(resource_parse, "generateIrradiance");

View file

@ -325,7 +325,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
auto gpuTexture = _channels[i]->getGPUTexture();
if (gpuTexture) {
gpuTexture->setSampler(sampler);
gpuTexture->autoGenerateMips(-1);
gpuTexture->setAutoGenerateMips(true);
}
batch.setResourceTexture((gpu::uint32)i, gpuTexture);
}

View file

@ -74,11 +74,11 @@ void AmbientOcclusionFramebuffer::allocate() {
auto width = _frameSize.x;
auto height = _frameSize.y;
_occlusionTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_occlusionTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion"));
_occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture);
_occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred"));
_occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture);
}

View file

@ -52,7 +52,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
_antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing"));
auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get<FramebufferCache>()->getLightingTexture()->getTexelFormat();
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
_antialiasingTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(format, width, height, defaultSampler));
_antialiasingTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
}

View file

@ -53,9 +53,9 @@ void DeferredFramebuffer::allocate() {
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
_deferredColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, defaultSampler));
_deferredNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(linearFormat, width, height, defaultSampler));
_deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, defaultSampler));
_deferredColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
_deferredNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(linearFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
_deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
_deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture);
_deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture);
@ -65,7 +65,7 @@ void DeferredFramebuffer::allocate() {
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
if (!_primaryDepthTexture) {
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height, defaultSampler));
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
}
_deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
@ -75,7 +75,7 @@ void DeferredFramebuffer::allocate() {
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR);
_lightingTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler));
_lightingTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, gpu::Texture::SINGLE_MIP, defaultSampler));
_lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("lighting"));
_lightingFramebuffer->setRenderBuffer(0, _lightingTexture);
_lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);

View file

@ -496,14 +496,14 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con
auto colorFormat = gpu::Element::COLOR_SRGBA_32;
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
auto primaryColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, defaultSampler));
auto primaryColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler));
_primaryFramebuffer->setRenderBuffer(0, primaryColorTexture);
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
auto primaryDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, defaultSampler));
auto primaryDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler));
_primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat);
}

View file

@ -168,8 +168,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
} else {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture());
}
} else {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
}
// Roughness map
@ -182,8 +180,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
}
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
}
// Normal map
@ -196,8 +192,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
}
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, nullptr);
}
// Metallic map
@ -210,8 +204,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
}
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, nullptr);
}
// Occlusion map
@ -224,8 +216,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
}
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, nullptr);
}
// Scattering map
@ -238,8 +228,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
}
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, nullptr);
}
// Emissive / Lightmap
@ -259,8 +247,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
}
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, nullptr);
}
}

View file

@ -73,11 +73,11 @@ void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const Rend
auto colorFormat = gpu::Element::COLOR_SRGBA_32;
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
auto colorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, defaultSampler));
auto colorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler));
_framebuffer->setRenderBuffer(0, colorTexture);
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
auto depthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, defaultSampler));
auto depthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler));
_framebuffer->setDepthStencilBuffer(depthTexture, depthFormat);
}

View file

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

View file

@ -72,18 +72,18 @@ void LinearDepthFramebuffer::allocate() {
auto height = _frameSize.y;
// For Linear Depth:
_linearDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height,
_linearDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, gpu::Texture::SINGLE_MIP,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth"));
_linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture);
_linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat());
// For Downsampling:
_halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y,
const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5;
_halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_halfLinearDepthTexture->autoGenerateMips(5);
_halfNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y,
_halfNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_downsampleFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("halfLinearDepth"));
@ -304,15 +304,15 @@ void SurfaceGeometryFramebuffer::allocate() {
auto width = _frameSize.x;
auto height = _frameSize.y;
_curvatureTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_curvatureTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_curvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::curvature"));
_curvatureFramebuffer->setRenderBuffer(0, _curvatureTexture);
_lowCurvatureTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_lowCurvatureTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_lowCurvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::lowCurvature"));
_lowCurvatureFramebuffer->setRenderBuffer(0, _lowCurvatureTexture);
_blurringTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_blurringTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_blurringFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("surfaceGeometry::blurring"));
_blurringFramebuffer->setRenderBuffer(0, _blurringTexture);
}

View file

@ -21,17 +21,17 @@ out vec4 outLinearDepth;
out vec4 outNormal;
void main(void) {
// Gather 2 by 2 quads from texture
// Gather 2 by 2 quads from texture and downsample
// Try different filters for Z
//vec4 Zeyes = textureGather(linearDepthMap, varTexCoord0, 0);
//float Zeye = min(min(Zeyes.x, Zeyes.y), min(Zeyes.z, Zeyes.w));
float Zeye = texture(linearDepthMap, varTexCoord0).x;
vec4 Zeyes = textureGather(linearDepthMap, varTexCoord0, 0);
// float Zeye = texture(linearDepthMap, varTexCoord0).x;
vec4 rawNormalsX = textureGather(normalMap, varTexCoord0, 0);
vec4 rawNormalsY = textureGather(normalMap, varTexCoord0, 1);
vec4 rawNormalsZ = textureGather(normalMap, varTexCoord0, 2);
float Zeye = min(min(Zeyes.x, Zeyes.y), min(Zeyes.z, Zeyes.w));
vec3 normal = vec3(0.0);
normal += unpackNormal(vec3(rawNormalsX[0], rawNormalsY[0], rawNormalsZ[0]));

View file

@ -207,7 +207,7 @@ void Font::read(QIODevice& in) {
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::BGRA);
}
_texture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(),
_texture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::SINGLE_MIP,
gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR)));
_texture->setStoredMipFormat(formatMip);
_texture->assignStoredMip(0, image.byteCount(), image.constBits());

View file

@ -108,7 +108,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
// _blurredFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat());
//}
auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler));
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler));
_blurredFramebuffer->setRenderBuffer(0, blurringTarget);
}
@ -131,7 +131,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
_outputFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat());
}*/
auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler));
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler));
_outputFramebuffer->setRenderBuffer(0, blurringTarget);
}

View file

@ -494,7 +494,7 @@ void OpenVrDisplayPlugin::customizeContext() {
_compositeInfos[0].texture = _compositeFramebuffer->getRenderBuffer(0);
for (size_t i = 0; i < COMPOSITING_BUFFER_SIZE; ++i) {
if (0 != i) {
_compositeInfos[i].texture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _renderTargetSize.x, _renderTargetSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT)));
_compositeInfos[i].texture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _renderTargetSize.x, _renderTargetSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT)));
}
_compositeInfos[i].textureID = getGLBackend()->getTextureID(_compositeInfos[i].texture);
}

View file

@ -1181,7 +1181,7 @@ function MyController(hand) {
this.updateStylusTip();
var DEFAULT_USE_FINGER_AS_STYLUS = true;
var DEFAULT_USE_FINGER_AS_STYLUS = false;
var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus");
if (USE_FINGER_AS_STYLUS === "") {
USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS;

View file

@ -81,6 +81,19 @@ body {
overflow-y: auto;
}
/* HACK
Makes entity properties dialog's scrollbar work on tablet such that don't need to keep pointer within scrollbar width when
using scroll handle.
*/
body {
padding-right: 0;
margin-right: -21px;
}
body > * {
margin-right: 42px;
}
/* END OF HACK */
table {
font-family: FiraSans-SemiBold;
font-size: 15px;

View file

@ -5,6 +5,93 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
*/
/*
CSS rules copied from edit-style.css.
Edit-style.css is not used in its entirety because don't want custom scrollbars; default scrollbar styling is used in order
to match other marketplace pages.
*/
@font-face {
font-family: Raleway-Regular;
src: url(../../../../resources/fonts/Raleway-Regular.ttf), /* Windows production */
url(../../../../fonts/Raleway-Regular.ttf), /* OSX production */
url(../../../../interface/resources/fonts/Raleway-Regular.ttf); /* Development, running script in /HiFi/examples */
}
@font-face {
font-family: Raleway-Bold;
src: url(../../../../resources/fonts/Raleway-Bold.ttf),
url(../../../../fonts/Raleway-Bold.ttf),
url(../../../../interface/resources/fonts/Raleway-Bold.ttf);
}
@font-face {
font-family: Raleway-SemiBold;
src: url(../../../../resources/fonts/Raleway-SemiBold.ttf),
url(../../../../fonts/Raleway-SemiBold.ttf),
url(../../../../interface/resources/fonts/Raleway-SemiBold.ttf);
}
@font-face {
font-family: FiraSans-SemiBold;
src: url(../../../../resources/fonts/FiraSans-SemiBold.ttf),
url(../../../../fonts/FiraSans-SemiBold.ttf),
url(../../../../interface/resources/fonts/FiraSans-SemiBold.ttf);
}
* {
margin: 0;
padding: 0;
}
body {
padding: 21px 21px 21px 21px;
color: #afafaf;
background-color: #404040;
font-family: Raleway-Regular;
font-size: 15px;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
overflow-x: hidden;
overflow-y: auto;
}
input[type=button] {
font-family: Raleway-Bold;
font-size: 13px;
text-transform: uppercase;
vertical-align: top;
height: 28px;
min-width: 120px;
padding: 0px 18px;
margin-right: 6px;
border-radius: 5px;
border: none;
color: #fff;
background-color: #000;
background: linear-gradient(#343434 20%, #000 100%);
cursor: pointer;
}
input[type=button].blue {
color: #fff;
background-color: #1080b8;
background: linear-gradient(#00b4ef 20%, #1080b8 100%);
}
/*
Marketplaces-specific CSS.
*/
body {
background: white;
padding: 0 0 0 0;

View file

@ -10,7 +10,6 @@
<head>
<title>Marketplaces</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link rel="stylesheet" type="text/css" href="css/edit-style.css">
<link rel="stylesheet" type="text/css" href="css/marketplaces.css">
<script src="js/jquery-2.1.4.min.js"></script>
</head>

View file

@ -72,7 +72,7 @@ function showMarketplace() {
tablet.webEventReceived.connect(function (message) {
if (message === GOTO_DIRECTORY) {
tablet.gotoWebScreen(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL);
tablet.gotoWebScreen(MARKETPLACES_URL, injectURL);
}
if (message === QUERY_CAN_WRITE_ASSETS) {

View file

@ -15,95 +15,94 @@
(function() { // BEGIN LOCAL_SCOPE
if (typeof String.prototype.startsWith != 'function') {
String.prototype.startsWith = function (str){
return this.slice(0, str.length) == str;
};
}
if (typeof String.prototype.endsWith != 'function') {
String.prototype.endsWith = function (str){
return this.slice(-str.length) == str;
};
}
if (typeof String.prototype.trimStartsWith != 'function') {
String.prototype.trimStartsWith = function (str){
if (this.startsWith(str)) {
return this.substr(str.length);
}
return this;
};
}
if (typeof String.prototype.trimEndsWith != 'function') {
String.prototype.trimEndsWith = function (str){
if (this.endsWith(str)) {
return this.substr(0,this.length - str.length);
}
return this;
};
const INPUT = "Input";
const OUTPUT = "Output";
function parseMenuItem(item) {
const USE = "Use ";
const FOR_INPUT = " for " + INPUT;
const FOR_OUTPUT = " for " + OUTPUT;
if (item.slice(0, USE.length) == USE) {
if (item.slice(-FOR_INPUT.length) == FOR_INPUT) {
return { device: item.slice(USE.length, -FOR_INPUT.length), mode: INPUT };
} else if (item.slice(-FOR_OUTPUT.length) == FOR_OUTPUT) {
return { device: item.slice(USE.length, -FOR_OUTPUT.length), mode: OUTPUT };
}
}
}
//
// VAR DEFINITIONS
//
var debugPrintStatements = true;
const INPUT_DEVICE_SETTING = "audio_input_device";
const OUTPUT_DEVICE_SETTING = "audio_output_device";
var audioDevicesList = [];
var wasHmdActive = false; // assume it's not active to start
var switchedAudioInputToHMD = false;
var switchedAudioOutputToHMD = false;
var previousSelectedInputAudioDevice = "";
var previousSelectedOutputAudioDevice = "";
var skipMenuEvents = true;
var selectedInputMenu = "";
var selectedOutputMenu = "";
var audioDevicesList = [];
function setupAudioMenus() {
removeAudioMenus();
Menu.addSeparator("Audio", "Input Audio Device");
var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING);
var inputDevices = AudioDevice.getInputDevices();
var selectedInputDevice = AudioDevice.getInputDevice();
if (inputDevices.indexOf(inputDeviceSetting) != -1 && selectedInputDevice != inputDeviceSetting) {
if (AudioDevice.setInputDevice(inputDeviceSetting)) {
selectedInputDevice = inputDeviceSetting;
}
//
// BEGIN FUNCTION DEFINITIONS
//
function debug() {
if (debugPrintStatements) {
print.apply(null, [].concat.apply(["selectAudioDevice.js:"], [].map.call(arguments, JSON.stringify)));
}
print("audio input devices: " + inputDevices);
for(var i = 0; i < inputDevices.length; i++) {
var thisDeviceSelected = (inputDevices[i] == selectedInputDevice);
var menuItem = "Use " + inputDevices[i] + " for Input";
}
function setupAudioMenus() {
// menu events can be triggered asynchronously; skip them for 200ms to avoid recursion and false switches
skipMenuEvents = true;
Script.setTimeout(function() { skipMenuEvents = false; }, 200);
removeAudioMenus();
// Setup audio input devices
Menu.addSeparator("Audio", "Input Audio Device");
var inputDevices = AudioDevice.getInputDevices();
for (var i = 0; i < inputDevices.length; i++) {
var audioDeviceMenuString = "Use " + inputDevices[i] + " for Input";
Menu.addMenuItem({
menuName: "Audio",
menuItemName: menuItem,
menuItemName: audioDeviceMenuString,
isCheckable: true,
isChecked: thisDeviceSelected
isChecked: inputDevices[i] == AudioDevice.getInputDevice()
});
audioDevicesList.push(menuItem);
if (thisDeviceSelected) {
selectedInputMenu = menuItem;
}
audioDevicesList.push(audioDeviceMenuString);
}
// Setup audio output devices
Menu.addSeparator("Audio", "Output Audio Device");
var outputDevices = AudioDevice.getOutputDevices();
for (var i = 0; i < outputDevices.length; i++) {
var audioDeviceMenuString = "Use " + outputDevices[i] + " for Output";
Menu.addMenuItem({
menuName: "Audio",
menuItemName: audioDeviceMenuString,
isCheckable: true,
isChecked: outputDevices[i] == AudioDevice.getOutputDevice()
});
audioDevicesList.push(audioDeviceMenuString);
}
}
function checkDeviceMismatch() {
var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING);
var interfaceInputDevice = AudioDevice.getInputDevice();
if (interfaceInputDevice != inputDeviceSetting) {
debug("Input Setting & Device mismatch! Input SETTING: " + inputDeviceSetting + "Input DEVICE IN USE: " + interfaceInputDevice);
switchAudioDevice("Use " + inputDeviceSetting + " for Input");
}
var outputDeviceSetting = Settings.getValue(OUTPUT_DEVICE_SETTING);
var outputDevices = AudioDevice.getOutputDevices();
var selectedOutputDevice = AudioDevice.getOutputDevice();
if (outputDevices.indexOf(outputDeviceSetting) != -1 && selectedOutputDevice != outputDeviceSetting) {
if (AudioDevice.setOutputDevice(outputDeviceSetting)) {
selectedOutputDevice = outputDeviceSetting;
}
}
print("audio output devices: " + outputDevices);
for (var i = 0; i < outputDevices.length; i++) {
var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice);
var menuItem = "Use " + outputDevices[i] + " for Output";
Menu.addMenuItem({
menuName: "Audio",
menuItemName: menuItem,
isCheckable: true,
isChecked: thisDeviceSelected
});
audioDevicesList.push(menuItem);
if (thisDeviceSelected) {
selectedOutputMenu = menuItem;
}
var interfaceOutputDevice = AudioDevice.getOutputDevice();
if (interfaceOutputDevice != outputDeviceSetting) {
debug("Output Setting & Device mismatch! Output SETTING: " + outputDeviceSetting + "Output DEVICE IN USE: " + interfaceOutputDevice);
switchAudioDevice("Use " + outputDeviceSetting + " for Output");
}
}
@ -112,130 +111,170 @@ function removeAudioMenus() {
Menu.removeSeparator("Audio", "Output Audio Device");
for (var index = 0; index < audioDevicesList.length; index++) {
Menu.removeMenuItem("Audio", audioDevicesList[index]);
if (Menu.menuItemExists("Audio", audioDevicesList[index])) {
Menu.removeMenuItem("Audio", audioDevicesList[index]);
}
}
Menu.removeMenu("Audio > Devices");
audioDevicesList = [];
}
function onDevicechanged() {
print("audio devices changed, removing Audio > Devices menu...");
Menu.removeMenu("Audio > Devices");
print("now setting up Audio > Devices menu");
debug("System audio devices changed. Removing and replacing Audio Menus...");
setupAudioMenus();
checkDeviceMismatch();
}
// Have a small delay before the menu's get setup and the audio devices can switch to the last selected ones
Script.setTimeout(function () {
print("connecting deviceChanged");
AudioDevice.deviceChanged.connect(onDevicechanged);
print("setting up Audio > Devices menu for first time");
setupAudioMenus();
}, 5000);
function scriptEnding() {
Menu.removeMenu("Audio > Devices");
function onMenuEvent(audioDeviceMenuString) {
if (!skipMenuEvents) {
switchAudioDevice(audioDeviceMenuString);
}
}
Script.scriptEnding.connect(scriptEnding);
function switchAudioDevice(audioDeviceMenuString) {
// if the device is not plugged in, short-circuit
if (!~audioDevicesList.indexOf(audioDeviceMenuString)) {
return;
}
function menuItemEvent(menuItem) {
if (menuItem.startsWith("Use ")) {
if (menuItem.endsWith(" for Output")) {
var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Output");
print("output audio selection..." + selectedDevice);
Menu.menuItemEvent.disconnect(menuItemEvent);
Menu.setIsOptionChecked(selectedOutputMenu, false);
selectedOutputMenu = menuItem;
Menu.setIsOptionChecked(selectedOutputMenu, true);
if (AudioDevice.setOutputDevice(selectedDevice)) {
Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice);
}
Menu.menuItemEvent.connect(menuItemEvent);
} else if (menuItem.endsWith(" for Input")) {
var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Input");
print("input audio selection..." + selectedDevice);
Menu.menuItemEvent.disconnect(menuItemEvent);
Menu.setIsOptionChecked(selectedInputMenu, false);
selectedInputMenu = menuItem;
Menu.setIsOptionChecked(selectedInputMenu, true);
var selection = parseMenuItem(audioDeviceMenuString);
if (!selection) {
debug("Invalid Audio audioDeviceMenuString! Doesn't end with 'for Input' or 'for Output'");
return;
}
// menu events can be triggered asynchronously; skip them for 200ms to avoid recursion and false switches
skipMenuEvents = true;
Script.setTimeout(function() { skipMenuEvents = false; }, 200);
var selectedDevice = selection.device;
if (selection.mode == INPUT) {
var currentInputDevice = AudioDevice.getInputDevice();
if (selectedDevice != currentInputDevice) {
debug("Switching audio INPUT device from " + currentInputDevice + " to " + selectedDevice);
Menu.setIsOptionChecked("Use " + currentInputDevice + " for Input", false);
if (AudioDevice.setInputDevice(selectedDevice)) {
Settings.setValue(INPUT_DEVICE_SETTING, selectedDevice);
Menu.setIsOptionChecked(audioDeviceMenuString, true);
} else {
debug("Error setting audio input device!")
Menu.setIsOptionChecked(audioDeviceMenuString, false);
}
Menu.menuItemEvent.connect(menuItemEvent);
} else {
debug("Selected input device is the same as the current input device!")
Settings.setValue(INPUT_DEVICE_SETTING, selectedDevice);
Menu.setIsOptionChecked(audioDeviceMenuString, true);
AudioDevice.setInputDevice(selectedDevice); // Still try to force-set the device (in case the user's trying to forcefully debug an issue)
}
} else if (selection.mode == OUTPUT) {
var currentOutputDevice = AudioDevice.getOutputDevice();
if (selectedDevice != currentOutputDevice) {
debug("Switching audio OUTPUT device from " + currentOutputDevice + " to " + selectedDevice);
Menu.setIsOptionChecked("Use " + currentOutputDevice + " for Output", false);
if (AudioDevice.setOutputDevice(selectedDevice)) {
Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice);
Menu.setIsOptionChecked(audioDeviceMenuString, true);
} else {
debug("Error setting audio output device!")
Menu.setIsOptionChecked(audioDeviceMenuString, false);
}
} else {
debug("Selected output device is the same as the current output device!")
Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice);
Menu.setIsOptionChecked(audioDeviceMenuString, true);
AudioDevice.setOutputDevice(selectedDevice); // Still try to force-set the device (in case the user's trying to forcefully debug an issue)
}
}
}
Menu.menuItemEvent.connect(menuItemEvent);
function restoreAudio() {
if (switchedAudioInputToHMD) {
debug("Switching back from HMD preferred audio input to: " + previousSelectedInputAudioDevice);
switchAudioDevice("Use " + previousSelectedInputAudioDevice + " for Input");
switchedAudioInputToHMD = false;
}
if (switchedAudioOutputToHMD) {
debug("Switching back from HMD preferred audio output to: " + previousSelectedOutputAudioDevice);
switchAudioDevice("Use " + previousSelectedOutputAudioDevice + " for Output");
switchedAudioOutputToHMD = false;
}
}
// Some HMDs (like Oculus CV1) have a built in audio device. If they
// do, then this function will handle switching to that device automatically
// when you goActive with the HMD active.
var wasHmdMounted = false; // assume it's un-mounted to start
var switchedAudioInputToHMD = false;
var switchedAudioOutputToHMD = false;
var previousSelectedInputAudioDevice = "";
var previousSelectedOutputAudioDevice = "";
function restoreAudio() {
if (switchedAudioInputToHMD) {
print("switching back from HMD preferred audio input to:" + previousSelectedInputAudioDevice);
menuItemEvent("Use " + previousSelectedInputAudioDevice + " for Input");
}
if (switchedAudioOutputToHMD) {
print("switching back from HMD preferred audio output to:" + previousSelectedOutputAudioDevice);
menuItemEvent("Use " + previousSelectedOutputAudioDevice + " for Output");
}
}
function checkHMDAudio() {
// Mounted state is changing... handle switching
if (HMD.mounted != wasHmdMounted) {
print("HMD mounted changed...");
// HMD Active state is changing; handle switching
if (HMD.active != wasHmdActive) {
debug("HMD Active state changed!");
// We're putting the HMD on... switch to those devices
if (HMD.mounted) {
print("NOW mounted...");
// We're putting the HMD on; switch to those devices
if (HMD.active) {
debug("HMD is now Active.");
var hmdPreferredAudioInput = HMD.preferredAudioInput();
var hmdPreferredAudioOutput = HMD.preferredAudioOutput();
print("hmdPreferredAudioInput:" + hmdPreferredAudioInput);
print("hmdPreferredAudioOutput:" + hmdPreferredAudioOutput);
debug("hmdPreferredAudioInput: " + hmdPreferredAudioInput);
debug("hmdPreferredAudioOutput: " + hmdPreferredAudioOutput);
var hmdHasPreferredAudio = (hmdPreferredAudioInput !== "") || (hmdPreferredAudioOutput !== "");
if (hmdHasPreferredAudio) {
print("HMD has preferred audio!");
if (hmdPreferredAudioInput !== "") {
debug("HMD has preferred audio input device.");
previousSelectedInputAudioDevice = Settings.getValue(INPUT_DEVICE_SETTING);
previousSelectedOutputAudioDevice = Settings.getValue(OUTPUT_DEVICE_SETTING);
print("previousSelectedInputAudioDevice:" + previousSelectedInputAudioDevice);
print("previousSelectedOutputAudioDevice:" + previousSelectedOutputAudioDevice);
if (hmdPreferredAudioInput != previousSelectedInputAudioDevice && hmdPreferredAudioInput !== "") {
print("switching to HMD preferred audio input to:" + hmdPreferredAudioInput);
debug("previousSelectedInputAudioDevice: " + previousSelectedInputAudioDevice);
if (hmdPreferredAudioInput != previousSelectedInputAudioDevice) {
switchedAudioInputToHMD = true;
menuItemEvent("Use " + hmdPreferredAudioInput + " for Input");
switchAudioDevice("Use " + hmdPreferredAudioInput + " for Input");
}
if (hmdPreferredAudioOutput != previousSelectedOutputAudioDevice && hmdPreferredAudioOutput !== "") {
print("switching to HMD preferred audio output to:" + hmdPreferredAudioOutput);
}
if (hmdPreferredAudioOutput !== "") {
debug("HMD has preferred audio output device.");
previousSelectedOutputAudioDevice = Settings.getValue(OUTPUT_DEVICE_SETTING);
debug("previousSelectedOutputAudioDevice: " + previousSelectedOutputAudioDevice);
if (hmdPreferredAudioOutput != previousSelectedOutputAudioDevice) {
switchedAudioOutputToHMD = true;
menuItemEvent("Use " + hmdPreferredAudioOutput + " for Output");
switchAudioDevice("Use " + hmdPreferredAudioOutput + " for Output");
}
}
} else {
print("HMD NOW un-mounted...");
debug("HMD no longer active. Restoring audio I/O devices...");
restoreAudio();
}
}
wasHmdMounted = HMD.mounted;
wasHmdActive = HMD.active;
}
Script.update.connect(checkHMDAudio);
//
// END FUNCTION DEFINITIONS
//
//
// BEGIN SCRIPT BODY
//
// Wait for the C++ systems to fire up before trying to do anything with audio devices
Script.setTimeout(function () {
debug("Connecting deviceChanged(), displayModeChanged(), and switchAudioDevice()...");
AudioDevice.deviceChanged.connect(onDevicechanged);
HMD.displayModeChanged.connect(checkHMDAudio);
Menu.menuItemEvent.connect(onMenuEvent);
debug("Setting up Audio I/O menu for the first time...");
setupAudioMenus();
checkDeviceMismatch();
debug("Checking HMD audio status...")
checkHMDAudio();
}, 3000);
debug("Connecting scriptEnding()");
Script.scriptEnding.connect(function () {
restoreAudio();
removeAudioMenus();
Menu.menuItemEvent.disconnect(menuItemEvent);
Script.update.disconnect(checkHMDAudio);
Menu.menuItemEvent.disconnect(onMenuEvent);
HMD.displayModeChanged.disconnect(checkHMDAudio);
AudioDevice.deviceChanged.disconnect(onDevicechanged);
});
//
// END SCRIPT BODY
//
}()); // END LOCAL_SCOPE