TRying to merge and expose counters for in flights transfers

This commit is contained in:
samcake 2016-04-05 12:18:30 -07:00
commit 710c4a1b8f
32 changed files with 625 additions and 309 deletions

View file

@ -495,7 +495,8 @@ function MyController(hand) {
} }
}; };
this.searchIndicatorOn = function(handPosition, distantPickRay) { this.searchIndicatorOn = function(distantPickRay) {
var handPosition = distantPickRay.origin;
var SEARCH_SPHERE_SIZE = 0.011; var SEARCH_SPHERE_SIZE = 0.011;
var SEARCH_SPHERE_FOLLOW_RATE = 0.50; var SEARCH_SPHERE_FOLLOW_RATE = 0.50;
@ -857,7 +858,9 @@ function MyController(hand) {
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation; var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation;
var currentControllerPosition = Controller.getPoseValue(controllerHandInput).position; var currentControllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation,
Controller.getPoseValue(controllerHandInput).translation),
MyAvatar.position);
var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation)); var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation));
var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ? var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ?
@ -865,19 +868,13 @@ function MyController(hand) {
var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation);
var distantPickRay = { var distantPickRay = {
origin: PICK_WITH_HAND_RAY ? handPosition : Camera.position, origin: PICK_WITH_HAND_RAY ? currentControllerPosition : Camera.position,
direction: PICK_WITH_HAND_RAY ? Quat.getUp(controllerRotation) : Vec3.mix(Quat.getUp(controllerRotation), direction: PICK_WITH_HAND_RAY ? Quat.getUp(controllerRotation) : Vec3.mix(Quat.getUp(controllerRotation),
Quat.getFront(Camera.orientation), Quat.getFront(Camera.orientation),
HAND_HEAD_MIX_RATIO), HAND_HEAD_MIX_RATIO),
length: PICK_MAX_DISTANCE length: PICK_MAX_DISTANCE
}; };
var searchVisualizationPickRay = {
origin: currentControllerPosition,
direction: Quat.getUp(this.getHandRotation()),
length: PICK_MAX_DISTANCE
};
// Pick at some maximum rate, not always // Pick at some maximum rate, not always
var pickRays = []; var pickRays = [];
var now = Date.now(); var now = Date.now();
@ -1086,7 +1083,7 @@ function MyController(hand) {
this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
} }
this.searchIndicatorOn(handPosition, distantPickRay); this.searchIndicatorOn(distantPickRay);
Reticle.setVisible(false); Reticle.setVisible(false);
}; };
@ -1668,7 +1665,7 @@ function MyController(hand) {
if (intersection.intersects) { if (intersection.intersects) {
this.intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); this.intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection);
} }
this.searchIndicatorOn(handPosition, pickRay); this.searchIndicatorOn(pickRay);
} }
} }

View file

@ -87,6 +87,11 @@ Item {
prop: "frameTextureCount", prop: "frameTextureCount",
label: "Frame", label: "Frame",
color: "#E2334D" color: "#E2334D"
},
{
prop: "textureGPUTransferCount",
label: "Transfer",
color: "#9495FF"
} }
] ]
} }

View file

@ -53,6 +53,10 @@ IceServer::IceServer(int argc, char* argv[]) :
QTimer* inactivePeerTimer = new QTimer(this); QTimer* inactivePeerTimer = new QTimer(this);
connect(inactivePeerTimer, &QTimer::timeout, this, &IceServer::clearInactivePeers); connect(inactivePeerTimer, &QTimer::timeout, this, &IceServer::clearInactivePeers);
inactivePeerTimer->start(CLEAR_INACTIVE_PEERS_INTERVAL_MSECS); inactivePeerTimer->start(CLEAR_INACTIVE_PEERS_INTERVAL_MSECS);
// handle public keys when they arrive from the QNetworkAccessManager
auto& networkAccessManager = NetworkAccessManager::getInstance();
connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished);
} }
bool IceServer::packetVersionMatch(const udt::Packet& packet) { bool IceServer::packetVersionMatch(const udt::Packet& packet) {
@ -200,7 +204,6 @@ bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& pla
void IceServer::requestDomainPublicKey(const QUuid& domainID) { void IceServer::requestDomainPublicKey(const QUuid& domainID) {
// send a request to the metaverse API for the public key for this domain // send a request to the metaverse API for the public key for this domain
auto& networkAccessManager = NetworkAccessManager::getInstance(); auto& networkAccessManager = NetworkAccessManager::getInstance();
connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished);
QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL }; QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL };
QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID)); QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID));

View file

@ -107,12 +107,15 @@ elseif(WIN32)
# add an executable that also has the icon itself and the configured rc file as resources # add an executable that also has the icon itself and the configured rc file as resources
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT}) add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT})
add_custom_command( if ( NOT DEV_BUILD )
TARGET ${TARGET_NAME} add_custom_command(
POST_BUILD TARGET ${TARGET_NAME}
COMMAND "mt.exe" -manifest "${CMAKE_CURRENT_SOURCE_DIR}/interface.exe.manifest" -inputresource:"$<TARGET_FILE:${TARGET_NAME}>"\;\#1 -outputresource:"$<TARGET_FILE:${TARGET_NAME}>"\;\#1 POST_BUILD
COMMENT "Adding OS version support manifest to exe" COMMAND "mt.exe" -manifest "${CMAKE_CURRENT_SOURCE_DIR}/interface.exe.manifest" -inputresource:"$<TARGET_FILE:${TARGET_NAME}>"\;\#1 -outputresource:"$<TARGET_FILE:${TARGET_NAME}>"\;\#1
) COMMENT "Adding OS version support manifest to exe"
)
endif()
else() else()
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
endif() endif()

View file

@ -144,9 +144,7 @@
#include "Util.h" #include "Util.h"
#include "InterfaceParentFinder.h" #include "InterfaceParentFinder.h"
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
// ON Windows PC, Nvidia Optimus laptop, we want to enable NVIDIA GPU
// FIXME seems to be broken. // FIXME seems to be broken.
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
extern "C" { extern "C" {
@ -1255,6 +1253,9 @@ void Application::initializeGL() {
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned // Where the gpuContext is initialized and where the TRUE Backend is created and assigned
gpu::Context::init<gpu::GLBackend>(); gpu::Context::init<gpu::GLBackend>();
_gpuContext = std::make_shared<gpu::Context>(); _gpuContext = std::make_shared<gpu::Context>();
// The gpu context can make child contexts for transfers, so
// we need to restore primary rendering context
_offscreenContext->makeCurrent();
initDisplay(); initDisplay();
qCDebug(interfaceapp, "Initialized Display."); qCDebug(interfaceapp, "Initialized Display.");
@ -1470,10 +1471,6 @@ void Application::paintGL() {
// update the avatar with a fresh HMD pose // update the avatar with a fresh HMD pose
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose()); getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
// update sensorToWorldMatrix for camera and hand controllers
getMyAvatar()->updateSensorToWorldMatrix();
auto lodManager = DependencyManager::get<LODManager>(); auto lodManager = DependencyManager::get<LODManager>();
@ -3406,6 +3403,9 @@ void Application::update(float deltaTime) {
avatarManager->updateOtherAvatars(deltaTime); avatarManager->updateOtherAvatars(deltaTime);
} }
// update sensorToWorldMatrix for camera and hand controllers
getMyAvatar()->updateSensorToWorldMatrix();
qApp->updateMyAvatarLookAtPosition(); qApp->updateMyAvatarLookAtPosition();
{ {

View file

@ -12,7 +12,7 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
// Qt Quick may need a depth and stencil buffer. Always make sure these are available. // Qt Quick may need a depth and stencil buffer. Always make sure these are available.
format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS); format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
format.setVersion(4, 1); format.setVersion(4, 5);
#ifdef DEBUG #ifdef DEBUG
format.setOption(QSurfaceFormat::DebugContext); format.setOption(QSurfaceFormat::DebugContext);
#endif #endif
@ -27,7 +27,7 @@ const QGLFormat& getDefaultGLFormat() {
static QGLFormat glFormat; static QGLFormat glFormat;
static std::once_flag once; static std::once_flag once;
std::call_once(once, [] { std::call_once(once, [] {
glFormat.setVersion(4, 1); glFormat.setVersion(4, 5);
glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0 glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0
glFormat.setSampleBuffers(false); glFormat.setSampleBuffers(false);
glFormat.setDepth(false); glFormat.setDepth(false);

View file

@ -83,3 +83,8 @@ void OffscreenGLCanvas::doneCurrent() {
QObject* OffscreenGLCanvas::getContextObject() { QObject* OffscreenGLCanvas::getContextObject() {
return _context; return _context;
} }
void OffscreenGLCanvas::moveToThreadWithContext(QThread* thread) {
moveToThread(thread);
_context->moveToThread(thread);
}

View file

@ -26,6 +26,7 @@ public:
bool create(QOpenGLContext* sharedContext = nullptr); bool create(QOpenGLContext* sharedContext = nullptr);
bool makeCurrent(); bool makeCurrent();
void doneCurrent(); void doneCurrent();
void moveToThreadWithContext(QThread* thread);
QOpenGLContext* getContext() { QOpenGLContext* getContext() {
return _context; return _context;
} }

View file

@ -6,8 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "OglplusHelpers.h" #include "OglplusHelpers.h"
#include <QSharedPointer>
#include <set> #include <set>
#include <oglplus/shapes/plane.hpp>
#include <oglplus/shapes/sky_box.hpp>
using namespace oglplus; using namespace oglplus;
using namespace oglplus::shapes; using namespace oglplus::shapes;
@ -20,11 +22,13 @@ uniform mat4 mvp = mat4(1);
in vec3 Position; in vec3 Position;
in vec2 TexCoord; in vec2 TexCoord;
out vec3 vPosition;
out vec2 vTexCoord; out vec2 vTexCoord;
void main() { void main() {
gl_Position = mvp * vec4(Position, 1); gl_Position = mvp * vec4(Position, 1);
vTexCoord = TexCoord ; vTexCoord = TexCoord;
vPosition = Position;
} }
)VS"; )VS";
@ -35,7 +39,9 @@ static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core
uniform sampler2D sampler; uniform sampler2D sampler;
uniform float alpha = 1.0; uniform float alpha = 1.0;
in vec3 vPosition;
in vec2 vTexCoord; in vec2 vTexCoord;
out vec4 FragColor; out vec4 FragColor;
void main() { void main() {
@ -47,12 +53,38 @@ void main() {
)FS"; )FS";
static const char * SIMPLE_TEXTURED_CUBEMAP_FS = R"FS(#version 410 core
#pragma line __LINE__
uniform samplerCube sampler;
uniform float alpha = 1.0;
in vec3 vPosition;
in vec3 vTexCoord;
out vec4 FragColor;
void main() {
FragColor = texture(sampler, vPosition);
FragColor.a *= alpha;
}
)FS";
ProgramPtr loadDefaultShader() { ProgramPtr loadDefaultShader() {
ProgramPtr result; ProgramPtr result;
compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS); compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS);
return result; return result;
} }
ProgramPtr loadCubemapShader() {
ProgramPtr result;
compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_CUBEMAP_FS);
return result;
}
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) { void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) {
using namespace oglplus; using namespace oglplus;
try { try {
@ -93,6 +125,10 @@ ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) {
); );
} }
ShapeWrapperPtr loadSkybox(ProgramPtr program) {
return ShapeWrapperPtr(new shapes::ShapeWrapper({ { "Position" } }, shapes::SkyBox(), *program));
}
// Return a point's cartesian coordinates on a sphere from pitch and yaw // Return a point's cartesian coordinates on a sphere from pitch and yaw
static glm::vec3 getPoint(float yaw, float pitch) { static glm::vec3 getPoint(float yaw, float pitch) {
return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),

View file

@ -37,7 +37,6 @@
#include <oglplus/bound/framebuffer.hpp> #include <oglplus/bound/framebuffer.hpp>
#include <oglplus/bound/renderbuffer.hpp> #include <oglplus/bound/renderbuffer.hpp>
#include <oglplus/shapes/wrapper.hpp> #include <oglplus/shapes/wrapper.hpp>
#include <oglplus/shapes/plane.hpp>
#ifdef _WIN32 #ifdef _WIN32
#pragma warning(pop) #pragma warning(pop)
@ -55,7 +54,9 @@ using ProgramPtr = std::shared_ptr<oglplus::Program>;
using Mat4Uniform = oglplus::Uniform<mat4>; using Mat4Uniform = oglplus::Uniform<mat4>;
ProgramPtr loadDefaultShader(); ProgramPtr loadDefaultShader();
ProgramPtr loadCubemapShader();
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs); void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs);
ShapeWrapperPtr loadSkybox(ProgramPtr program);
ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f); ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f);
ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32); ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32);

View file

@ -13,6 +13,9 @@
#include <QOpenGLContext> #include <QOpenGLContext>
QOpenGLContext* QOpenGLContextWrapper::currentContext() {
return QOpenGLContext::currentContext();
}
QOpenGLContextWrapper::QOpenGLContextWrapper() : QOpenGLContextWrapper::QOpenGLContextWrapper() :
_context(new QOpenGLContext) _context(new QOpenGLContext)

View file

@ -19,7 +19,6 @@ class QSurfaceFormat;
class QOpenGLContextWrapper { class QOpenGLContextWrapper {
public: public:
QOpenGLContextWrapper(); QOpenGLContextWrapper();
void setFormat(const QSurfaceFormat& format); void setFormat(const QSurfaceFormat& format);
bool create(); bool create();
void swapBuffers(QSurface* surface); void swapBuffers(QSurface* surface);
@ -27,6 +26,8 @@ public:
void doneCurrent(); void doneCurrent();
void setShareContext(QOpenGLContext* otherContext); void setShareContext(QOpenGLContext* otherContext);
static QOpenGLContext* currentContext();
QOpenGLContext* getContext() { QOpenGLContext* getContext() {
return _context; return _context;
} }

View file

@ -115,6 +115,7 @@ std::atomic<Buffer::Size> Context::_bufferGPUMemoryUsage{ 0 };
std::atomic<uint32_t> Context::_textureGPUCount{ 0 }; std::atomic<uint32_t> Context::_textureGPUCount{ 0 };
std::atomic<Texture::Size> Context::_textureGPUMemoryUsage{ 0 }; std::atomic<Texture::Size> Context::_textureGPUMemoryUsage{ 0 };
std::atomic<Texture::Size> Context::_textureGPUVirtualMemoryUsage{ 0 }; std::atomic<Texture::Size> Context::_textureGPUVirtualMemoryUsage{ 0 };
std::atomic<uint32_t> Context::_textureGPUTransferCount{ 0 };
void Context::incrementBufferGPUCount() { void Context::incrementBufferGPUCount() {
_bufferGPUCount++; _bufferGPUCount++;
@ -161,6 +162,13 @@ void Context::updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newOb
} }
} }
void Context::incrementTextureGPUTransferCount() {
_textureGPUTransferCount++;
}
void Context::decrementTextureGPUTransferCount() {
_textureGPUTransferCount--;
}
uint32_t Context::getBufferGPUCount() { uint32_t Context::getBufferGPUCount() {
return _bufferGPUCount.load(); return _bufferGPUCount.load();
} }
@ -181,6 +189,10 @@ Context::Size Context::getTextureGPUVirtualMemoryUsage() {
return _textureGPUVirtualMemoryUsage.load(); return _textureGPUVirtualMemoryUsage.load();
} }
uint32_t Context::getTextureGPUTransferCount() {
return _textureGPUTransferCount.load();
}
void Backend::incrementBufferGPUCount() { Context::incrementBufferGPUCount(); } void Backend::incrementBufferGPUCount() { Context::incrementBufferGPUCount(); }
void Backend::decrementBufferGPUCount() { Context::decrementBufferGPUCount(); } void Backend::decrementBufferGPUCount() { Context::decrementBufferGPUCount(); }
void Backend::updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateBufferGPUMemoryUsage(prevObjectSize, newObjectSize); } void Backend::updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateBufferGPUMemoryUsage(prevObjectSize, newObjectSize); }
@ -188,4 +200,5 @@ void Backend::incrementTextureGPUCount() { Context::incrementTextureGPUCount();
void Backend::decrementTextureGPUCount() { Context::decrementTextureGPUCount(); } void Backend::decrementTextureGPUCount() { Context::decrementTextureGPUCount(); }
void Backend::updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUMemoryUsage(prevObjectSize, newObjectSize); } void Backend::updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUMemoryUsage(prevObjectSize, newObjectSize); }
void Backend::updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUVirtualMemoryUsage(prevObjectSize, newObjectSize); } void Backend::updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUVirtualMemoryUsage(prevObjectSize, newObjectSize); }
void Backend::incrementTextureGPUTransferCount() { Context::incrementTextureGPUTransferCount(); }
void Backend::decrementTextureGPUTransferCount() { Context::decrementTextureGPUTransferCount(); }

View file

@ -130,6 +130,8 @@ public:
static void decrementTextureGPUCount(); static void decrementTextureGPUCount();
static void updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize); static void updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
static void updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize); static void updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
static void incrementTextureGPUTransferCount();
static void decrementTextureGPUTransferCount();
protected: protected:
StereoState _stereo; StereoState _stereo;
@ -180,6 +182,7 @@ public:
static uint32_t getTextureGPUCount(); static uint32_t getTextureGPUCount();
static Size getTextureGPUMemoryUsage(); static Size getTextureGPUMemoryUsage();
static Size getTextureGPUVirtualMemoryUsage(); static Size getTextureGPUVirtualMemoryUsage();
static uint32_t getTextureGPUTransferCount();
protected: protected:
Context(const Context& context); Context(const Context& context);
@ -206,6 +209,8 @@ protected:
static void decrementTextureGPUCount(); static void decrementTextureGPUCount();
static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize); static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
static void updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newObjectSize); static void updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newObjectSize);
static void incrementTextureGPUTransferCount();
static void decrementTextureGPUTransferCount();
// Buffer and Texture Counters // Buffer and Texture Counters
static std::atomic<uint32_t> _bufferGPUCount; static std::atomic<uint32_t> _bufferGPUCount;
@ -214,6 +219,8 @@ protected:
static std::atomic<uint32_t> _textureGPUCount; static std::atomic<uint32_t> _textureGPUCount;
static std::atomic<Size> _textureGPUMemoryUsage; static std::atomic<Size> _textureGPUMemoryUsage;
static std::atomic<Size> _textureGPUVirtualMemoryUsage; static std::atomic<Size> _textureGPUVirtualMemoryUsage;
static std::atomic<uint32_t> _textureGPUTransferCount;
friend class Backend; friend class Backend;
}; };

View file

@ -125,6 +125,7 @@ GLBackend::GLBackend() {
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment); glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
initInput(); initInput();
initTransform(); initTransform();
initTextureTransferHelper();
} }
GLBackend::~GLBackend() { GLBackend::~GLBackend() {

View file

@ -24,6 +24,8 @@
namespace gpu { namespace gpu {
class GLTextureTransferHelper;
class GLBackend : public Backend { class GLBackend : public Backend {
// Context Backend static interface required // Context Backend static interface required
@ -35,7 +37,6 @@ class GLBackend : public Backend {
explicit GLBackend(bool syncCache); explicit GLBackend(bool syncCache);
GLBackend(); GLBackend();
public: public:
virtual ~GLBackend(); virtual ~GLBackend();
virtual void render(Batch& batch); virtual void render(Batch& batch);
@ -75,12 +76,12 @@ public:
class GLTexture : public GPUObject { class GLTexture : public GPUObject {
public: public:
Stamp _storageStamp; const Stamp _storageStamp;
Stamp _contentStamp; Stamp _contentStamp { 0 };
GLuint _texture; const GLuint _texture;
GLenum _target; const GLenum _target;
GLTexture(); GLTexture(const gpu::Texture& gpuTexture);
~GLTexture(); ~GLTexture();
GLuint size() const { return _size; } GLuint size() const { return _size; }
@ -88,18 +89,59 @@ public:
void updateSize(GLuint virtualSize); void updateSize(GLuint virtualSize);
enum SyncState {
// The texture is currently undergoing no processing, although it's content
// may be out of date, or it's storage may be invalid relative to the
// owning GPU texture
Idle,
// The texture has been queued for transfer to the GPU
Pending,
// The texture has been transferred to the GPU, but is awaiting
// any post transfer operations that may need to occur on the
// primary rendering thread
Transferred,
};
void setSyncState(SyncState syncState) { _syncState = syncState; }
SyncState getSyncState() const { return _syncState; }
// Is the storage out of date relative to the gpu texture?
bool isInvalid() const;
// Is the content out of date relative to the gpu texture?
bool isOutdated() const;
// Is the texture in a state where it can be rendered with no work?
bool isReady() const;
// Move the image bits from the CPU to the GPU
void transfer() const;
// Execute any post-move operations that must occur only on the main thread
void postTransfer();
static const size_t CUBE_NUM_FACES = 6;
static const GLenum CUBE_FACE_LAYOUT[6];
private: private:
void setSize(GLuint size); void setSize(GLuint size);
void setVirtualSize(GLuint size); void setVirtualSize(GLuint size);
GLuint _size; // true size as reported by the gl api GLuint _size; // true size as reported by the gl api
GLuint _virtualSize; // theorical size as expected GLuint _virtualSize; // theorical size as expected
void transferMip(GLenum target, const Texture::PixelsPointer& mip) const;
// The owning texture
const Texture& _gpuTexture;
std::atomic<SyncState> _syncState { SyncState::Idle };
}; };
static GLTexture* syncGPUObject(const Texture& texture); static GLTexture* syncGPUObject(const TexturePointer& texture);
static GLuint getTextureID(const TexturePointer& texture, bool sync = true); static GLuint getTextureID(const TexturePointer& texture, bool sync = true);
// very specific for now // very specific for now
static void syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object); static void syncSampler(const Sampler& sampler, Texture::Type type, const GLTexture* object);
class GLShader : public GPUObject { class GLShader : public GPUObject {
public: public:
@ -247,6 +289,11 @@ protected:
void renderPassTransfer(Batch& batch); void renderPassTransfer(Batch& batch);
void renderPassDraw(Batch& batch); void renderPassDraw(Batch& batch);
void initTextureTransferHelper();
static void transferGPUObject(const TexturePointer& texture);
static std::shared_ptr<GLTextureTransferHelper> _textureTransferHelper;
// Draw Stage // Draw Stage
void do_draw(Batch& batch, size_t paramOffset); void do_draw(Batch& batch, size_t paramOffset);
void do_drawIndexed(Batch& batch, size_t paramOffset); void do_drawIndexed(Batch& batch, size_t paramOffset);
@ -490,6 +537,7 @@ protected:
typedef void (GLBackend::*CommandCall)(Batch&, size_t); typedef void (GLBackend::*CommandCall)(Batch&, size_t);
static CommandCall _commandCalls[Batch::NUM_COMMANDS]; static CommandCall _commandCalls[Batch::NUM_COMMANDS];
}; };
}; };

View file

@ -83,7 +83,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
for (auto& b : framebuffer.getRenderBuffers()) { for (auto& b : framebuffer.getRenderBuffers()) {
surface = b._texture; surface = b._texture;
if (surface) { if (surface) {
gltexture = GLBackend::syncGPUObject(*surface); gltexture = GLBackend::syncGPUObject(surface);
} else { } else {
gltexture = nullptr; gltexture = nullptr;
} }
@ -123,7 +123,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
if (framebuffer.getDepthStamp() != object->_depthStamp) { if (framebuffer.getDepthStamp() != object->_depthStamp) {
auto surface = framebuffer.getDepthStencilBuffer(); auto surface = framebuffer.getDepthStencilBuffer();
if (framebuffer.hasDepthStencil() && surface) { if (framebuffer.hasDepthStencil() && surface) {
gltexture = GLBackend::syncGPUObject(*surface); gltexture = GLBackend::syncGPUObject(surface);
} }
if (gltexture) { if (gltexture) {

View file

@ -255,7 +255,7 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) {
_stats._RSNumTextureBounded++; _stats._RSNumTextureBounded++;
// Always make sure the GLObject is in sync // Always make sure the GLObject is in sync
GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); GLTexture* object = GLBackend::syncGPUObject(resourceTexture);
if (object) { if (object) {
GLuint to = object->_texture; GLuint to = object->_texture;
GLuint target = object->_target; GLuint target = object->_target;

View file

@ -51,7 +51,9 @@ public:
GLenum format; GLenum format;
GLenum type; GLenum type;
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat) {
return evalGLTexelFormat(dstFormat, dstFormat);
}
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat); static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat);
}; };

View file

@ -22,7 +22,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getSemantic()) { switch (dstFormat.getSemantic()) {
case gpu::RGB: case gpu::RGB:
case gpu::RGBA: case gpu::RGBA:
texel.internalFormat = GL_RED; texel.internalFormat = GL_R8;
break; break;
case gpu::COMPRESSED_R: case gpu::COMPRESSED_R:
@ -30,7 +30,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
break; break;
case gpu::DEPTH: case gpu::DEPTH:
texel.internalFormat = GL_DEPTH_COMPONENT; texel.internalFormat = GL_DEPTH_COMPONENT32;
break; break;
case gpu::DEPTH_STENCIL: case gpu::DEPTH_STENCIL:
texel.type = GL_UNSIGNED_INT_24_8; texel.type = GL_UNSIGNED_INT_24_8;
@ -50,7 +50,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getSemantic()) { switch (dstFormat.getSemantic()) {
case gpu::RGB: case gpu::RGB:
case gpu::RGBA: case gpu::RGBA:
texel.internalFormat = GL_RG; texel.internalFormat = GL_RG8;
break; break;
default: default:
qCDebug(gpulogging) << "Unknown combination of texel format"; qCDebug(gpulogging) << "Unknown combination of texel format";
@ -67,7 +67,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getSemantic()) { switch (dstFormat.getSemantic()) {
case gpu::RGB: case gpu::RGB:
case gpu::RGBA: case gpu::RGBA:
texel.internalFormat = GL_RGB; texel.internalFormat = GL_RGB8;
break; break;
case gpu::COMPRESSED_RGB: case gpu::COMPRESSED_RGB:
texel.internalFormat = GL_COMPRESSED_RGB; texel.internalFormat = GL_COMPRESSED_RGB;
@ -101,16 +101,16 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getSemantic()) { switch (dstFormat.getSemantic()) {
case gpu::RGB: case gpu::RGB:
texel.internalFormat = GL_RGB; texel.internalFormat = GL_RGB8;
break; break;
case gpu::RGBA: case gpu::RGBA:
texel.internalFormat = GL_RGBA; texel.internalFormat = GL_RGBA8;
break; break;
case gpu::SRGB: case gpu::SRGB:
texel.internalFormat = GL_SRGB; texel.internalFormat = GL_SRGB8;
break; break;
case gpu::SRGBA: case gpu::SRGBA:
texel.internalFormat = GL_SRGB_ALPHA; texel.internalFormat = GL_SRGB8_ALPHA8;
break; break;
case gpu::COMPRESSED_RGBA: case gpu::COMPRESSED_RGBA:
@ -148,7 +148,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
} }
return texel; return texel;
} else { } else {
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }; GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
switch (dstFormat.getDimension()) { switch (dstFormat.getDimension()) {
case gpu::SCALAR: { case gpu::SCALAR: {
@ -171,11 +171,11 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
break; break;
} }
case gpu::NUINT32: { case gpu::NUINT32: {
texel.internalFormat = GL_RED; texel.internalFormat = GL_R8;
break; break;
} }
case gpu::NINT32: { case gpu::NINT32: {
texel.internalFormat = GL_RED_SNORM; texel.internalFormat = GL_R8_SNORM;
break; break;
} }
case gpu::FLOAT: { case gpu::FLOAT: {
@ -212,7 +212,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
} }
case gpu::NUINT8: { case gpu::NUINT8: {
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
texel.internalFormat = GL_SLUMINANCE; texel.internalFormat = GL_SLUMINANCE8;
} else { } else {
texel.internalFormat = GL_R8; texel.internalFormat = GL_R8;
} }
@ -237,7 +237,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
case gpu::DEPTH: case gpu::DEPTH:
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
texel.internalFormat = GL_DEPTH_COMPONENT; texel.internalFormat = GL_DEPTH_COMPONENT32;
switch (dstFormat.getType()) { switch (dstFormat.getType()) {
case gpu::UINT32: case gpu::UINT32:
case gpu::INT32: case gpu::INT32:
@ -289,7 +289,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getSemantic()) { switch (dstFormat.getSemantic()) {
case gpu::RGB: case gpu::RGB:
case gpu::RGBA: case gpu::RGBA:
texel.internalFormat = GL_RG; texel.internalFormat = GL_RG8;
break; break;
default: default:
qCDebug(gpulogging) << "Unknown combination of texel format"; qCDebug(gpulogging) << "Unknown combination of texel format";
@ -306,11 +306,11 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getSemantic()) { switch (dstFormat.getSemantic()) {
case gpu::RGB: case gpu::RGB:
case gpu::RGBA: case gpu::RGBA:
texel.internalFormat = GL_RGB; texel.internalFormat = GL_RGB8;
break; break;
case gpu::SRGB: case gpu::SRGB:
case gpu::SRGBA: case gpu::SRGBA:
texel.internalFormat = GL_SRGB; // standard 2.2 gamma correction color texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color
break; break;
default: default:
qCDebug(gpulogging) << "Unknown combination of texel format"; qCDebug(gpulogging) << "Unknown combination of texel format";
@ -324,10 +324,10 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getSemantic()) { switch (dstFormat.getSemantic()) {
case gpu::RGB: case gpu::RGB:
texel.internalFormat = GL_RGB; texel.internalFormat = GL_RGB8;
break; break;
case gpu::RGBA: case gpu::RGBA:
texel.internalFormat = GL_RGBA; texel.internalFormat = GL_RGBA8;
switch (dstFormat.getType()) { switch (dstFormat.getType()) {
case gpu::UINT32: case gpu::UINT32:
texel.format = GL_RGBA_INTEGER; texel.format = GL_RGBA_INTEGER;
@ -383,10 +383,10 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
} }
break; break;
case gpu::SRGB: case gpu::SRGB:
texel.internalFormat = GL_SRGB; texel.internalFormat = GL_SRGB8;
break; break;
case gpu::SRGBA: case gpu::SRGBA:
texel.internalFormat = GL_SRGB_ALPHA; // standard 2.2 gamma correction color texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
break; break;
default: default:
qCDebug(gpulogging) << "Unknown combination of texel format"; qCDebug(gpulogging) << "Unknown combination of texel format";

View file

@ -9,19 +9,83 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "GPULogging.h" #include "GPULogging.h"
#include <QtCore/QThread>
#include "GLBackendShared.h" #include "GLBackendShared.h"
#include "GLBackendTextureTransfer.h"
using namespace gpu; using namespace gpu;
GLBackend::GLTexture::GLTexture() : GLenum gpuToGLTextureType(const Texture& texture) {
_storageStamp(0), switch (texture.getType()) {
_contentStamp(0), case Texture::TEX_2D:
_texture(0), return GL_TEXTURE_2D;
_target(GL_TEXTURE_2D), break;
case Texture::TEX_CUBE:
return GL_TEXTURE_CUBE_MAP;
break;
default:
qFatal("Unsupported texture type");
}
Q_UNREACHABLE();
return GL_TEXTURE_2D;
}
GLuint allocateSingleTexture() {
GLuint result;
glGenTextures(1, &result);
return result;
}
const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
// Create the texture and allocate storage
GLBackend::GLTexture::GLTexture(const Texture& texture) :
_storageStamp(texture.getStamp()),
_texture(allocateSingleTexture()),
_target(gpuToGLTextureType(texture)),
_size(0), _size(0),
_virtualSize(0) _virtualSize(0),
_gpuTexture(texture)
{ {
Backend::incrementTextureGPUCount(); Backend::incrementTextureGPUCount();
Backend::updateTextureGPUMemoryUsage(0, _size);
Backend::setGPUObject(texture, this);
GLsizei width = texture.getWidth();
GLsizei height = texture.getHeight();
GLsizei levels = 1;
if (texture.maxMip() > 0) {
if (texture.isAutogenerateMips()) {
while ((width | height) >> levels) {
++levels;
}
}
levels = std::max(1, std::min(texture.maxMip() + 1, levels));
}
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat());
withPreservedTexture(_target, [&] {
glBindTexture(_target, _texture);
(void)CHECK_GL_ERROR();
// GO through the process of allocating the correct storage
if (GLEW_VERSION_4_2) {
glTexStorage2D(_target, levels, texelFormat.internalFormat, width, height);
} else {
glTexImage2D(_target, 0, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, 0);
}
(void)CHECK_GL_ERROR();
syncSampler(texture.getSampler(), texture.getType(), this);
(void)CHECK_GL_ERROR();
updateSize((GLuint)texture.evalTotalSize());
});
} }
GLBackend::GLTexture::~GLTexture() { GLBackend::GLTexture::~GLTexture() {
@ -33,6 +97,10 @@ GLBackend::GLTexture::~GLTexture() {
Backend::decrementTextureGPUCount(); Backend::decrementTextureGPUCount();
} }
bool GLBackend::GLTexture::isInvalid() const {
return _storageStamp < _gpuTexture.getStamp();
}
void GLBackend::GLTexture::setSize(GLuint size) { void GLBackend::GLTexture::setSize(GLuint size) {
Backend::updateTextureGPUMemoryUsage(_size, size); Backend::updateTextureGPUMemoryUsage(_size, size);
_size = size; _size = size;
@ -68,195 +136,143 @@ void GLBackend::GLTexture::updateSize(GLuint virtualSize) {
} }
} }
GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
// If GPU object already created and in sync bool GLBackend::GLTexture::isOutdated() const {
bool needUpdate = false; return _contentStamp < _gpuTexture.getDataStamp();
if (object && (object->_storageStamp == texture.getStamp())) { }
// If gpu object info is in sync with sysmem version
if (object->_contentStamp >= texture.getDataStamp()) { bool GLBackend::GLTexture::isReady() const {
// Then all good, GPU object is ready to be used // If we have an invalid texture, we're never ready
return object; if (isInvalid()) {
} else { return false;
// Need to update the content of the GPU object from the source sysmem of the texture }
needUpdate = true;
} // If we're out of date, but the transfer is in progress, report ready
} else if (!texture.isDefined()) { // as a special case
auto syncState = _syncState.load();
if (isOutdated()) {
return Pending == syncState;
}
return Idle == syncState;
}
// Move content bits from the CPU to the GPU for a given mip / face
void GLBackend::GLTexture::transferMip(GLenum target, const Texture::PixelsPointer& mip) const {
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat(), mip->getFormat());
glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData());
(void)CHECK_GL_ERROR();
}
// Move content bits from the CPU to the GPU
void GLBackend::GLTexture::transfer() const {
PROFILE_RANGE(__FUNCTION__);
qDebug() << "Transferring texture: " << _texture;
// Need to update the content of the GPU object from the source sysmem of the texture
if (_contentStamp >= _gpuTexture.getDataStamp()) {
return;
}
glBindTexture(_target, _texture);
// GO through the process of allocating the correct storage and/or update the content
switch (_gpuTexture.getType()) {
case Texture::TEX_2D:
if (_gpuTexture.isStoredMipFaceAvailable(0)) {
transferMip(GL_TEXTURE_2D, _gpuTexture.accessStoredMipFace(0));
}
break;
case Texture::TEX_CUBE:
// transfer pixels from each faces
for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) {
if (_gpuTexture.isStoredMipFaceAvailable(0, f)) {
transferMip(CUBE_FACE_LAYOUT[f], _gpuTexture.accessStoredMipFace(0, f));
}
}
break;
default:
qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported";
break;
}
if (_gpuTexture.isAutogenerateMips()) {
glGenerateMipmap(_target);
(void)CHECK_GL_ERROR();
}
}
// Do any post-transfer operations that might be required on the main context / rendering thread
void GLBackend::GLTexture::postTransfer() {
setSyncState(GLTexture::Idle);
// At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory
switch (_gpuTexture.getType()) {
case Texture::TEX_2D:
_gpuTexture.notifyMipFaceGPULoaded(0, 0);
break;
case Texture::TEX_CUBE:
for (uint8_t f = 0; f < CUBE_NUM_FACES; ++f) {
_gpuTexture.notifyMipFaceGPULoaded(0, f);
}
break;
default:
qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported";
break;
}
}
GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) {
const Texture& texture = *texturePointer;
if (!texture.isDefined()) {
// NO texture definition yet so let's avoid thinking // NO texture definition yet so let's avoid thinking
return nullptr; return nullptr;
} }
// If the object hasn't been created, or the object definition is out of date, drop and re-create
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
if (object && object->isReady()) {
return object;
}
// Object isn't ready, check what we need to do...
// Create the texture if need be (force re-creation if the storage stamp changes
// for easier use of immutable storage)
if (!object || object->isInvalid()) {
// This automatically destroys the old texture
object = new GLTexture(texture);
}
// need to have a gpu object? // need to have a gpu object?
if (!object) { if (texture.getNumSlices() != 1) {
object = new GLTexture(); return object;
glGenTextures(1, &object->_texture);
(void) CHECK_GL_ERROR();
Backend::setGPUObject(texture, object);
} }
// GO through the process of allocating the correct storage and/or update the content // Object might be outdated, if so, start the transfer
switch (texture.getType()) { // (outdated objects that are already in transfer will have reported 'true' for ready()
case Texture::TEX_2D: { if (object->isOutdated()) {
if (texture.getNumSlices() == 1) { Backend::incrementTextureGPUTransferCount();
GLint boundTex = -1; _textureTransferHelper->transferTexture(texturePointer);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
glBindTexture(GL_TEXTURE_2D, object->_texture);
if (needUpdate) {
if (texture.isStoredMipFaceAvailable(0)) {
Texture::PixelsPointer mip = texture.accessStoredMipFace(0);
const GLvoid* bytes = mip->readData();
Element srcFormat = mip->getFormat();
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
glBindTexture(GL_TEXTURE_2D, object->_texture);
glTexSubImage2D(GL_TEXTURE_2D, 0,
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
texelFormat.format, texelFormat.type, bytes);
if (texture.isAutogenerateMips()) {
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
object->_target = GL_TEXTURE_2D;
syncSampler(texture.getSampler(), texture.getType(), object);
// At this point the mip piels have been loaded, we can notify
texture.notifyMipFaceGPULoaded(0, 0);
object->_contentStamp = texture.getDataStamp();
object->updateSize((GLuint)texture.evalTotalSize());
}
} else {
const GLvoid* bytes = 0;
Element srcFormat = texture.getTexelFormat();
if (texture.isStoredMipFaceAvailable(0)) {
Texture::PixelsPointer mip = texture.accessStoredMipFace(0);
bytes = mip->readData();
srcFormat = mip->getFormat();
object->_contentStamp = texture.getDataStamp();
}
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
glTexImage2D(GL_TEXTURE_2D, 0,
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
texelFormat.format, texelFormat.type, bytes);
if (bytes && texture.isAutogenerateMips()) {
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
object->_target = GL_TEXTURE_2D;
syncSampler(texture.getSampler(), texture.getType(), object);
// At this point the mip pixels have been loaded, we can notify
texture.notifyMipFaceGPULoaded(0, 0);
object->_storageStamp = texture.getStamp();
object->_contentStamp = texture.getDataStamp();
object->updateSize((GLuint)texture.evalTotalSize());
}
glBindTexture(GL_TEXTURE_2D, boundTex);
}
break;
} }
case Texture::TEX_CUBE: {
if (texture.getNumSlices() == 1) {
GLint boundTex = -1;
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture);
const int NUM_FACES = 6;
const GLenum FACE_LAYOUT[] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z };
if (needUpdate) {
glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture);
// transfer pixels from each faces if (GLTexture::Transferred == object->getSyncState()) {
for (int f = 0; f < NUM_FACES; f++) { Backend::decrementTextureGPUTransferCount();
if (texture.isStoredMipFaceAvailable(0, f)) { object->postTransfer();
Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f);
Element srcFormat = mipFace->getFormat();
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
glTexSubImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0,
texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData()));
// At this point the mip pixels have been loaded, we can notify
texture.notifyMipFaceGPULoaded(0, f);
}
}
if (texture.isAutogenerateMips()) {
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
object->_target = GL_TEXTURE_CUBE_MAP;
syncSampler(texture.getSampler(), texture.getType(), object);
object->_contentStamp = texture.getDataStamp();
object->updateSize((GLuint)texture.evalTotalSize());
} else {
glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture);
// transfer pixels from each faces
for (int f = 0; f < NUM_FACES; f++) {
if (texture.isStoredMipFaceAvailable(0, f)) {
Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f);
Element srcFormat = mipFace->getFormat();
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
glTexImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0,
texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData()));
// At this point the mip pixels have been loaded, we can notify
texture.notifyMipFaceGPULoaded(0, f);
}
}
if (texture.isAutogenerateMips()) {
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
object->_target = GL_TEXTURE_CUBE_MAP;
syncSampler(texture.getSampler(), texture.getType(), object);
object->_storageStamp = texture.getStamp();
object->_contentStamp = texture.getDataStamp();
object->updateSize((GLuint)texture.evalTotalSize());
}
glBindTexture(GL_TEXTURE_CUBE_MAP, boundTex);
}
break;
} }
default:
qCDebug(gpulogging) << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported";
}
(void) CHECK_GL_ERROR();
return object; return object;
} }
std::shared_ptr<GLTextureTransferHelper> GLBackend::_textureTransferHelper;
void GLBackend::initTextureTransferHelper() {
_textureTransferHelper = std::make_shared<GLTextureTransferHelper>();
}
GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) { GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) {
if (!texture) { if (!texture) {
@ -264,7 +280,7 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) {
} }
GLTexture* object { nullptr }; GLTexture* object { nullptr };
if (sync) { if (sync) {
object = GLBackend::syncGPUObject(*texture); object = GLBackend::syncGPUObject(texture);
} else { } else {
object = Backend::getGPUObject<GLBackend::GLTexture>(*texture); object = Backend::getGPUObject<GLBackend::GLTexture>(*texture);
} }
@ -275,38 +291,37 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) {
} }
} }
void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object) { void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, const GLTexture* object) {
if (!object) return; if (!object) return;
if (!object->_texture) return;
class GLFilterMode { class GLFilterMode {
public: public:
GLint minFilter; GLint minFilter;
GLint magFilter; GLint magFilter;
}; };
static const GLFilterMode filterModes[] = { static const GLFilterMode filterModes[] = {
{GL_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_POINT, { GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT,
{GL_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR, { GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR,
{GL_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT, { GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT,
{GL_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR, { GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR,
{GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT,
{GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT,
{GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_MAG_POINT_MIP_LINEAR, { GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR,
{GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, { GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
{GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_POINT_MAG_MIP_LINEAR, { GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_POINT_MAG_MIP_LINEAR,
{GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_MIP_POINT, { GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_MIP_POINT,
{GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, { GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
{GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR_MIP_POINT, { GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR_MIP_POINT,
{GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_MIP_LINEAR, { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_MIP_LINEAR,
{GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} //FILTER_ANISOTROPIC, { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR } //FILTER_ANISOTROPIC,
}; };
auto fm = filterModes[sampler.getFilter()]; auto fm = filterModes[sampler.getFilter()];
glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter);
glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter);
static const GLenum comparisonFuncs[] = { static const GLenum comparisonFuncs[] = {
GL_NEVER, GL_NEVER,
GL_LESS, GL_LESS,
GL_EQUAL, GL_EQUAL,
@ -323,7 +338,7 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur
glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
} }
static const GLenum wrapModes[] = { static const GLenum wrapModes[] = {
GL_REPEAT, // WRAP_REPEAT, GL_REPEAT, // WRAP_REPEAT,
GL_MIRRORED_REPEAT, // WRAP_MIRROR, GL_MIRRORED_REPEAT, // WRAP_MIRROR,
GL_CLAMP_TO_EDGE, // WRAP_CLAMP, GL_CLAMP_TO_EDGE, // WRAP_CLAMP,
@ -334,23 +349,20 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur
glTexParameteri(object->_target, GL_TEXTURE_WRAP_T, wrapModes[sampler.getWrapModeV()]); glTexParameteri(object->_target, GL_TEXTURE_WRAP_T, wrapModes[sampler.getWrapModeV()]);
glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]); glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]);
glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*) &sampler.getBorderColor()); glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset()); glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset());
glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float) sampler.getMinMip()); glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
} }
void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) { void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) {
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
if (!resourceTexture) { if (!resourceTexture) {
return; return;
} }
GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); GLTexture* object = GLBackend::syncGPUObject(resourceTexture);
if (!object) { if (!object) {
return; return;
} }
@ -365,7 +377,7 @@ void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) {
if (freeSlot < 0) { if (freeSlot < 0) {
// If had to use slot 0 then restore state // If had to use slot 0 then restore state
GLTexture* boundObject = GLBackend::syncGPUObject(*_resource._textures[0]); GLTexture* boundObject = GLBackend::syncGPUObject(_resource._textures[0]);
if (boundObject) { if (boundObject) {
glBindTexture(boundObject->_target, boundObject->_texture); glBindTexture(boundObject->_target, boundObject->_texture);
} }

View file

@ -0,0 +1,76 @@
//
// Created by Bradley Austin Davis on 2016/04/03
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendTextureTransfer.h"
#include "GLBackendShared.h"
#ifdef THREADED_TEXTURE_TRANSFER
#include <gl/OffscreenGLCanvas.h>
#include <gl/QOpenGLContextWrapper.h>
#endif
using namespace gpu;
GLTextureTransferHelper::GLTextureTransferHelper() {
#ifdef THREADED_TEXTURE_TRANSFER
_canvas = std::make_shared<OffscreenGLCanvas>();
_canvas->create(QOpenGLContextWrapper::currentContext());
if (!_canvas->makeCurrent()) {
qFatal("Unable to create texture transfer context");
}
_canvas->doneCurrent();
initialize(true, QThread::LowPriority);
_canvas->moveToThreadWithContext(_thread);
#endif
}
void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) {
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
#ifdef THREADED_TEXTURE_TRANSFER
TextureTransferPackage package { texturePointer, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0) };
glFlush();
object->setSyncState(GLBackend::GLTexture::Pending);
queueItem(package);
#else
object->transfer();
object->setSyncState(GLBackend::GLTexture::Transferred);
#endif
}
void GLTextureTransferHelper::setup() {
#ifdef THREADED_TEXTURE_TRANSFER
_canvas->makeCurrent();
#endif
}
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
for (auto package : messages) {
glWaitSync(package.fence, 0, GL_TIMEOUT_IGNORED);
glDeleteSync(package.fence);
TexturePointer texturePointer = package.texture.lock();
// Texture no longer exists, move on to the next
if (!texturePointer) {
continue;
}
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
object->transfer();
glBindTexture(object->_target, 0);
auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
glDeleteSync(writeSync);
object->_contentStamp = texturePointer->getDataStamp();
object->setSyncState(GLBackend::GLTexture::Transferred);
}
return true;
}

View file

@ -0,0 +1,61 @@
//
// Created by Bradley Austin Davis on 2016/04/03
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <GenericQueueThread.h>
#include "GLBackendShared.h"
#define THREADED_TEXTURE_TRANSFER
class OffscreenGLCanvas;
namespace gpu {
struct TextureTransferPackage {
std::weak_ptr<Texture> texture;
GLsync fence;
};
class GLTextureTransferHelper : public GenericQueueThread<TextureTransferPackage> {
public:
GLTextureTransferHelper();
void transferTexture(const gpu::TexturePointer& texturePointer);
void postTransfer(const gpu::TexturePointer& texturePointer);
protected:
void setup() override;
bool processQueueItems(const Queue& messages) override;
void transferTextureSynchronous(const gpu::Texture& texture);
private:
std::shared_ptr<OffscreenGLCanvas> _canvas;
};
template <typename F>
void withPreservedTexture(GLenum target, F f) {
GLint boundTex = -1;
switch (target) {
case GL_TEXTURE_2D:
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
break;
case GL_TEXTURE_CUBE_MAP:
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
break;
default:
qFatal("Unsupported texture type");
}
(void)CHECK_GL_ERROR();
f();
glBindTexture(target, boundTex);
(void)CHECK_GL_ERROR();
}
}

View file

@ -52,6 +52,10 @@ Texture::Size Texture::getTextureGPUVirtualMemoryUsage() {
return Context::getTextureGPUVirtualMemoryUsage(); return Context::getTextureGPUVirtualMemoryUsage();
} }
uint32_t Texture::getTextureGPUTransferCount() {
return Context::getTextureGPUTransferCount();
}
uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = { 1, 1, 1, 6 }; uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = { 1, 1, 1, 6 };
Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :

View file

@ -147,6 +147,7 @@ public:
static uint32_t getTextureGPUCount(); static uint32_t getTextureGPUCount();
static Size getTextureGPUMemoryUsage(); static Size getTextureGPUMemoryUsage();
static Size getTextureGPUVirtualMemoryUsage(); static Size getTextureGPUVirtualMemoryUsage();
static uint32_t getTextureGPUTransferCount();
class Usage { class Usage {
public: public:

View file

@ -13,20 +13,22 @@
#include <mutex> #include <mutex>
#include <glm/glm.hpp>
#include <glm/gtc/random.hpp>
#include <QNetworkReply> #include <QNetworkReply>
#include <QPainter> #include <QPainter>
#include <QRunnable> #include <QRunnable>
#include <QThreadPool> #include <QThreadPool>
#include <qimagereader.h> #include <QImageReader>
#include <shared/NsightHelpers.h> #include <glm/glm.hpp>
#include <PathUtils.h> #include <glm/gtc/random.hpp>
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <shared/NsightHelpers.h>
#include <Finally.h>
#include <PathUtils.h>
#include "ModelNetworkingLogging.h" #include "ModelNetworkingLogging.h"
TextureCache::TextureCache() { TextureCache::TextureCache() {
@ -198,7 +200,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
{ {
_textureLoader = textureLoader; _textureLoader = textureLoader;
} }
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
switch (_type) { switch (_type) {
case ALBEDO_TEXTURE: { case ALBEDO_TEXTURE: {
@ -253,14 +255,14 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
class ImageReader : public QRunnable { class ImageReader : public QRunnable {
public: public:
ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data, const QUrl& url = QUrl()); ImageReader(const QWeakPointer<Resource>& resource, const QByteArray& data, const QUrl& url = QUrl());
virtual void run(); virtual void run();
private: private:
static void listSupportedImageFormats(); static void listSupportedImageFormats();
QWeakPointer<Resource> _texture; QWeakPointer<Resource> _resource;
QUrl _url; QUrl _url;
QByteArray _content; QByteArray _content;
}; };
@ -274,9 +276,9 @@ void NetworkTexture::loadContent(const QByteArray& content) {
QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url)); QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url));
} }
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data, ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QByteArray& data,
const QUrl& url) : const QUrl& url) :
_texture(texture), _resource(resource),
_url(url), _url(url),
_content(data) _content(data)
{ {
@ -297,26 +299,28 @@ void ImageReader::run() {
originalPriority = QThread::NormalPriority; originalPriority = QThread::NormalPriority;
} }
QThread::currentThread()->setPriority(QThread::LowPriority); QThread::currentThread()->setPriority(QThread::LowPriority);
Finally restorePriority([originalPriority]{
QThread::currentThread()->setPriority(originalPriority);
});
auto texture = _texture.toStrongRef(); if (!_resource.data()) {
if (!texture) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
qCWarning(modelnetworking) << "Could not get strong ref";
return; return;
} }
listSupportedImageFormats(); listSupportedImageFormats();
// try to help the QImage loader by extracting the image file format from the url filename ext // Help the QImage loader by extracting the image file format from the url filename ext.
// Some tga are not created properly for example without it // Some tga are not created properly without it.
auto filename = _url.fileName().toStdString(); auto filename = _url.fileName().toStdString();
auto filenameExtension = filename.substr(filename.find_last_of('.') + 1); auto filenameExtension = filename.substr(filename.find_last_of('.') + 1);
QImage image = QImage::fromData(_content, filenameExtension.c_str()); QImage image = QImage::fromData(_content, filenameExtension.c_str());
// Note that QImage.format is the pixel format which is different from the "format" of the image file... // Note that QImage.format is the pixel format which is different from the "format" of the image file...
auto imageFormat = image.format(); auto imageFormat = image.format();
int originalWidth = image.width(); int originalWidth = image.width();
int originalHeight = image.height(); int originalHeight = image.height();
if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) {
if (filenameExtension.empty()) { if (filenameExtension.empty()) {
qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url; qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url;
@ -326,26 +330,40 @@ void ImageReader::run() {
return; return;
} }
gpu::Texture* theTexture = nullptr; gpu::Texture* texture = nullptr;
auto ntex = texture.dynamicCast<NetworkTexture>(); {
if (ntex) { // Double-check the resource still exists between long operations.
auto resource = _resource.toStrongRef();
if (!resource) {
qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
return;
}
auto url = _url.toString().toStdString();
PROFILE_RANGE_EX(__FUNCTION__"::textureLoader", 0xffffff00, nullptr); PROFILE_RANGE_EX(__FUNCTION__"::textureLoader", 0xffffff00, nullptr);
theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString()); texture = resource.dynamicCast<NetworkTexture>()->getTextureLoader()(image, url);
} }
QMetaObject::invokeMethod(texture.data(), "setImage", // Ensure the resource has not been deleted, and won't be while invokeMethod is in flight.
Q_ARG(void*, theTexture), auto resource = _resource.toStrongRef();
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); if (!resource) {
QThread::currentThread()->setPriority(originalPriority); qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
delete texture;
} else {
QMetaObject::invokeMethod(resource.data(), "setImage", Qt::BlockingQueuedConnection,
Q_ARG(void*, texture),
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
}
} }
void NetworkTexture::setImage(void* voidTexture, int originalWidth, void NetworkTexture::setImage(void* voidTexture, int originalWidth,
int originalHeight) { int originalHeight) {
_originalWidth = originalWidth; _originalWidth = originalWidth;
_originalHeight = originalHeight; _originalHeight = originalHeight;
gpu::Texture* texture = static_cast<gpu::Texture*>(voidTexture); gpu::Texture* texture = static_cast<gpu::Texture*>(voidTexture);
// Passing ownership // Passing ownership
_textureSource->resetTexture(texture); _textureSource->resetTexture(texture);
auto gpuTexture = _textureSource->getGPUTexture(); auto gpuTexture = _textureSource->getGPUTexture();

View file

@ -336,6 +336,7 @@ void NodeList::sendDomainServerCheckIn() {
if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
// we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS
// so emit our signal that says that // so emit our signal that says that
qDebug() << "Limit of silent domain checkins reached";
emit limitOfSilentDomainCheckInsReached(); emit limitOfSilentDomainCheckInsReached();
} }

View file

@ -384,9 +384,10 @@ int Octree::readElementData(OctreeElementPointer destinationElement, const unsig
// check the exists mask to see if we have a child to traverse into // check the exists mask to see if we have a child to traverse into
if (oneAtBit(childInBufferMask, childIndex)) { if (oneAtBit(childInBufferMask, childIndex)) {
if (!destinationElement->getChildAtIndex(childIndex)) { auto childAt = destinationElement->getChildAtIndex(childIndex);
if (!childAt) {
// add a child at that index, if it doesn't exist // add a child at that index, if it doesn't exist
destinationElement->addChildAtIndex(childIndex); childAt = destinationElement->addChildAtIndex(childIndex);
bool nodeIsDirty = destinationElement->isDirty(); bool nodeIsDirty = destinationElement->isDirty();
if (nodeIsDirty) { if (nodeIsDirty) {
_isDirty = true; _isDirty = true;
@ -394,8 +395,7 @@ int Octree::readElementData(OctreeElementPointer destinationElement, const unsig
} }
// tell the child to read the subsequent data // tell the child to read the subsequent data
int lowerLevelBytes = readElementData(destinationElement->getChildAtIndex(childIndex), int lowerLevelBytes = readElementData(childAt, nodeData + bytesRead, bytesLeftToRead, args);
nodeData + bytesRead, bytesLeftToRead, args);
bytesRead += lowerLevelBytes; bytesRead += lowerLevelBytes;
bytesLeftToRead -= lowerLevelBytes; bytesLeftToRead -= lowerLevelBytes;

View file

@ -33,6 +33,7 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte
config->textureCPUMemoryUsage = gpu::Texture::getTextureCPUMemoryUsage(); config->textureCPUMemoryUsage = gpu::Texture::getTextureCPUMemoryUsage();
config->textureGPUMemoryUsage = gpu::Texture::getTextureGPUMemoryUsage(); config->textureGPUMemoryUsage = gpu::Texture::getTextureGPUMemoryUsage();
config->textureGPUVirtualMemoryUsage = gpu::Texture::getTextureGPUVirtualMemoryUsage(); config->textureGPUVirtualMemoryUsage = gpu::Texture::getTextureGPUVirtualMemoryUsage();
config->textureGPUTransferCount = gpu::Texture::getTextureGPUTransferCount();
gpu::ContextStats gpuStats(_gpuStats); gpu::ContextStats gpuStats(_gpuStats);
renderContext->args->_context->getStats(_gpuStats); renderContext->args->_context->getStats(_gpuStats);

View file

@ -34,6 +34,7 @@ namespace render {
Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty) Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty)
Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage NOTIFY dirty) Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage NOTIFY dirty)
Q_PROPERTY(qint64 textureGPUVirtualMemoryUsage MEMBER textureGPUVirtualMemoryUsage NOTIFY dirty) Q_PROPERTY(qint64 textureGPUVirtualMemoryUsage MEMBER textureGPUVirtualMemoryUsage NOTIFY dirty)
Q_PROPERTY(quint32 textureGPUTransferCount MEMBER textureGPUTransferCount NOTIFY dirty)
Q_PROPERTY(quint32 frameAPIDrawcallCount MEMBER frameAPIDrawcallCount NOTIFY dirty) Q_PROPERTY(quint32 frameAPIDrawcallCount MEMBER frameAPIDrawcallCount NOTIFY dirty)
Q_PROPERTY(quint32 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty) Q_PROPERTY(quint32 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty)
@ -59,6 +60,7 @@ namespace render {
qint64 textureCPUMemoryUsage{ 0 }; qint64 textureCPUMemoryUsage{ 0 };
qint64 textureGPUMemoryUsage{ 0 }; qint64 textureGPUMemoryUsage{ 0 };
qint64 textureGPUVirtualMemoryUsage{ 0 }; qint64 textureGPUVirtualMemoryUsage{ 0 };
quint32 textureGPUTransferCount{ 0 };
quint32 frameAPIDrawcallCount{ 0 }; quint32 frameAPIDrawcallCount{ 0 };
quint32 frameDrawcallCount{ 0 }; quint32 frameDrawcallCount{ 0 };

View file

@ -46,6 +46,8 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) {
_thread->start(); _thread->start();
_thread->setPriority(priority); _thread->setPriority(priority);
} else {
setup();
} }
} }
@ -60,10 +62,16 @@ void GenericThread::terminate() {
_thread->deleteLater(); _thread->deleteLater();
_thread = NULL; _thread = NULL;
} }
} else {
shutdown();
} }
} }
void GenericThread::threadRoutine() { void GenericThread::threadRoutine() {
if (_isThreaded) {
setup();
}
while (!_stopThread) { while (!_stopThread) {
// override this function to do whatever your class actually does, return false to exit thread early // override this function to do whatever your class actually does, return false to exit thread early
@ -78,8 +86,13 @@ void GenericThread::threadRoutine() {
} }
} }
// If we were on a thread, then quit our thread if (_isThreaded) {
if (_isThreaded && _thread) { shutdown();
_thread->quit();
// If we were on a thread, then quit our thread
if (_thread) {
_thread->quit();
}
} }
} }

View file

@ -33,9 +33,6 @@ public:
/// Call to stop the thread /// Call to stop the thread
void terminate(); void terminate();
/// Override this function to do whatever your class actually does, return false to exit thread early.
virtual bool process() = 0;
virtual void terminating() { }; // lets your subclass know we're terminating, and it should respond appropriately virtual void terminating() { }; // lets your subclass know we're terminating, and it should respond appropriately
bool isThreaded() const { return _isThreaded; } bool isThreaded() const { return _isThreaded; }
@ -48,6 +45,10 @@ signals:
void finished(); void finished();
protected: protected:
/// Override this function to do whatever your class actually does, return false to exit thread early.
virtual bool process() = 0;
virtual void setup() {};
virtual void shutdown() {};
/// Locks all the resources of the thread. /// Locks all the resources of the thread.
void lock() { _mutex.lock(); } void lock() { _mutex.lock(); }