mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #7536 from samcake/orange
First pass at using compressed format when uploading textures
This commit is contained in:
commit
460fdc0761
21 changed files with 1017 additions and 848 deletions
|
@ -84,6 +84,11 @@ Item {
|
|||
prop: "frameTextureCount",
|
||||
label: "Frame",
|
||||
color: "#E2334D"
|
||||
},
|
||||
{
|
||||
prop: "textureGPUTransferCount",
|
||||
label: "Transfer",
|
||||
color: "#9495FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -104,7 +109,18 @@ Item {
|
|||
prop: "textureGPUMemoryUsage",
|
||||
label: "GPU",
|
||||
color: "#1AC567"
|
||||
},
|
||||
{
|
||||
prop: "textureGPUVirtualMemoryUsage",
|
||||
label: "GPU Virtual",
|
||||
color: "#9495FF"
|
||||
},
|
||||
{
|
||||
prop: "frameTextureMemoryUsage",
|
||||
label: "Frame",
|
||||
color: "#E2334D"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -179,7 +195,7 @@ Item {
|
|||
object: Render.getConfig("DrawLight"),
|
||||
prop: "numDrawn",
|
||||
label: "Lights",
|
||||
color: "#E2334D"
|
||||
color: "#FED959"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -114,6 +114,8 @@ std::atomic<Buffer::Size> Context::_bufferGPUMemoryUsage{ 0 };
|
|||
|
||||
std::atomic<uint32_t> Context::_textureGPUCount{ 0 };
|
||||
std::atomic<Texture::Size> Context::_textureGPUMemoryUsage{ 0 };
|
||||
std::atomic<Texture::Size> Context::_textureGPUVirtualMemoryUsage{ 0 };
|
||||
std::atomic<uint32_t> Context::_textureGPUTransferCount{ 0 };
|
||||
|
||||
void Context::incrementBufferGPUCount() {
|
||||
_bufferGPUCount++;
|
||||
|
@ -149,6 +151,24 @@ void Context::updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSiz
|
|||
}
|
||||
}
|
||||
|
||||
void Context::updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newObjectSize) {
|
||||
if (prevObjectSize == newObjectSize) {
|
||||
return;
|
||||
}
|
||||
if (newObjectSize > prevObjectSize) {
|
||||
_textureGPUVirtualMemoryUsage.fetch_add(newObjectSize - prevObjectSize);
|
||||
} else {
|
||||
_textureGPUVirtualMemoryUsage.fetch_sub(prevObjectSize - newObjectSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::incrementTextureGPUTransferCount() {
|
||||
_textureGPUTransferCount++;
|
||||
}
|
||||
void Context::decrementTextureGPUTransferCount() {
|
||||
_textureGPUTransferCount--;
|
||||
}
|
||||
|
||||
uint32_t Context::getBufferGPUCount() {
|
||||
return _bufferGPUCount.load();
|
||||
}
|
||||
|
@ -165,10 +185,20 @@ Context::Size Context::getTextureGPUMemoryUsage() {
|
|||
return _textureGPUMemoryUsage.load();
|
||||
}
|
||||
|
||||
Context::Size Context::getTextureGPUVirtualMemoryUsage() {
|
||||
return _textureGPUVirtualMemoryUsage.load();
|
||||
}
|
||||
|
||||
uint32_t Context::getTextureGPUTransferCount() {
|
||||
return _textureGPUTransferCount.load();
|
||||
}
|
||||
|
||||
void Backend::incrementBufferGPUCount() { Context::incrementBufferGPUCount(); }
|
||||
void Backend::decrementBufferGPUCount() { Context::decrementBufferGPUCount(); }
|
||||
void Backend::updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateBufferGPUMemoryUsage(prevObjectSize, newObjectSize); }
|
||||
void Backend::incrementTextureGPUCount() { Context::incrementTextureGPUCount(); }
|
||||
void Backend::decrementTextureGPUCount() { Context::decrementTextureGPUCount(); }
|
||||
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::incrementTextureGPUTransferCount() { Context::incrementTextureGPUTransferCount(); }
|
||||
void Backend::decrementTextureGPUTransferCount() { Context::decrementTextureGPUTransferCount(); }
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
int _ISNumIndexBufferChanges = 0;
|
||||
|
||||
int _RSNumTextureBounded = 0;
|
||||
int _RSAmountTextureMemoryBounded = 0;
|
||||
|
||||
int _DSNumAPIDrawcalls = 0;
|
||||
int _DSNumDrawcalls = 0;
|
||||
|
@ -128,6 +129,9 @@ public:
|
|||
static void incrementTextureGPUCount();
|
||||
static void decrementTextureGPUCount();
|
||||
static void updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
|
||||
static void updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
|
||||
static void incrementTextureGPUTransferCount();
|
||||
static void decrementTextureGPUTransferCount();
|
||||
|
||||
protected:
|
||||
StereoState _stereo;
|
||||
|
@ -177,6 +181,8 @@ public:
|
|||
|
||||
static uint32_t getTextureGPUCount();
|
||||
static Size getTextureGPUMemoryUsage();
|
||||
static Size getTextureGPUVirtualMemoryUsage();
|
||||
static uint32_t getTextureGPUTransferCount();
|
||||
|
||||
protected:
|
||||
Context(const Context& context);
|
||||
|
@ -202,6 +208,9 @@ protected:
|
|||
static void incrementTextureGPUCount();
|
||||
static void decrementTextureGPUCount();
|
||||
static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||
static void updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||
static void incrementTextureGPUTransferCount();
|
||||
static void decrementTextureGPUTransferCount();
|
||||
|
||||
// Buffer and Texture Counters
|
||||
static std::atomic<uint32_t> _bufferGPUCount;
|
||||
|
@ -209,6 +218,9 @@ protected:
|
|||
|
||||
static std::atomic<uint32_t> _textureGPUCount;
|
||||
static std::atomic<Size> _textureGPUMemoryUsage;
|
||||
static std::atomic<Size> _textureGPUVirtualMemoryUsage;
|
||||
static std::atomic<uint32_t> _textureGPUTransferCount;
|
||||
|
||||
|
||||
friend class Backend;
|
||||
};
|
||||
|
|
|
@ -192,6 +192,25 @@ enum Semantic {
|
|||
SRGBA,
|
||||
SBGRA,
|
||||
|
||||
// These are generic compression format smeantic for images
|
||||
_FIRST_COMPRESSED,
|
||||
COMPRESSED_R,
|
||||
|
||||
COMPRESSED_RGB,
|
||||
COMPRESSED_RGBA,
|
||||
|
||||
COMPRESSED_SRGB,
|
||||
COMPRESSED_SRGBA,
|
||||
|
||||
// FIXME: Will have to be supported later:
|
||||
/*COMPRESSED_BC3_RGBA, // RGBA_S3TC_DXT5_EXT,
|
||||
COMPRESSED_BC3_SRGBA, // SRGB_ALPHA_S3TC_DXT5_EXT
|
||||
|
||||
COMPRESSED_BC7_RGBA,
|
||||
COMPRESSED_BC7_SRGBA, */
|
||||
|
||||
_LAST_COMPRESSED,
|
||||
|
||||
R11G11B10,
|
||||
|
||||
UNIFORM,
|
||||
|
@ -224,6 +243,7 @@ public:
|
|||
|
||||
Dimension getDimension() const { return (Dimension)_dimension; }
|
||||
|
||||
bool isCompressed() const { return uint8(getSemantic() - _FIRST_COMPRESSED) <= uint8(_LAST_COMPRESSED - _FIRST_COMPRESSED); }
|
||||
|
||||
Type getType() const { return (Type)_type; }
|
||||
bool isNormalized() const { return (getType() >= NORMALIZED_START); }
|
||||
|
|
|
@ -76,15 +76,22 @@ public:
|
|||
|
||||
class GLTexture : public GPUObject {
|
||||
public:
|
||||
// The public gl texture object
|
||||
GLuint _texture{ 0 };
|
||||
|
||||
const Stamp _storageStamp;
|
||||
Stamp _contentStamp { 0 };
|
||||
const GLuint _texture;
|
||||
const GLenum _target;
|
||||
|
||||
GLTexture(const gpu::Texture& gpuTexture);
|
||||
~GLTexture();
|
||||
|
||||
void createTexture();
|
||||
|
||||
GLuint size() const { return _size; }
|
||||
GLuint virtualSize() const { return _virtualSize; }
|
||||
|
||||
void updateSize();
|
||||
|
||||
enum SyncState {
|
||||
// The texture is currently undergoing no processing, although it's content
|
||||
|
@ -119,16 +126,26 @@ public:
|
|||
|
||||
static const size_t CUBE_NUM_FACES = 6;
|
||||
static const GLenum CUBE_FACE_LAYOUT[6];
|
||||
|
||||
|
||||
private:
|
||||
// at creation the true texture is created in GL
|
||||
// it becomes public only when ready.
|
||||
GLuint _privateTexture{ 0 };
|
||||
|
||||
void setSize(GLuint size);
|
||||
void setVirtualSize(GLuint size);
|
||||
|
||||
GLuint _size; // true size as reported by the gl api
|
||||
GLuint _virtualSize; // theorical size as expected
|
||||
GLuint _numLevels{ 0 };
|
||||
|
||||
void transferMip(GLenum target, const Texture::PixelsPointer& mip) const;
|
||||
|
||||
const GLuint _size;
|
||||
// The owning texture
|
||||
const Texture& _gpuTexture;
|
||||
std::atomic<SyncState> _syncState { SyncState::Idle };
|
||||
};
|
||||
static GLTexture* syncGPUObject(const TexturePointer& texture);
|
||||
static GLTexture* syncGPUObject(const TexturePointer& texture, bool needTransfer = true);
|
||||
static GLuint getTextureID(const TexturePointer& texture, bool sync = true);
|
||||
|
||||
// very specific for now
|
||||
|
|
|
@ -83,7 +83,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
|
|||
for (auto& b : framebuffer.getRenderBuffers()) {
|
||||
surface = b._texture;
|
||||
if (surface) {
|
||||
gltexture = GLBackend::syncGPUObject(surface);
|
||||
gltexture = GLBackend::syncGPUObject(surface, false); // Grab the gltexture and don't transfer
|
||||
} else {
|
||||
gltexture = nullptr;
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
|
|||
if (framebuffer.getDepthStamp() != object->_depthStamp) {
|
||||
auto surface = framebuffer.getDepthStencilBuffer();
|
||||
if (framebuffer.hasDepthStencil() && surface) {
|
||||
gltexture = GLBackend::syncGPUObject(surface);
|
||||
gltexture = GLBackend::syncGPUObject(surface, false); // Grab the gltexture and don't transfer
|
||||
}
|
||||
|
||||
if (gltexture) {
|
||||
|
|
|
@ -266,6 +266,8 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) {
|
|||
|
||||
_resource._textures[slot] = resourceTexture;
|
||||
|
||||
_stats._RSAmountTextureMemoryBounded += object->size();
|
||||
|
||||
} else {
|
||||
releaseResourceTexture(slot);
|
||||
return;
|
||||
|
|
|
@ -45,6 +45,20 @@ static const GLenum _elementTypeToGLType[gpu::NUM_TYPES] = {
|
|||
GL_UNSIGNED_BYTE
|
||||
};
|
||||
|
||||
class GLTexelFormat {
|
||||
public:
|
||||
GLenum internalFormat;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
|
||||
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat) {
|
||||
return evalGLTexelFormat(dstFormat, dstFormat);
|
||||
}
|
||||
static GLTexelFormat evalGLTexelFormatInternal(const gpu::Element& dstFormat);
|
||||
|
||||
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat);
|
||||
};
|
||||
|
||||
// Stupid preprocessor trick to turn the line macro into a string
|
||||
#define CHECK_GL_ERROR_HELPER(x) #x
|
||||
// FIXME doesn't build on Linux or Mac. Hmmmm
|
||||
|
|
426
libraries/gpu/src/gpu/GLBackendTexelFormat.cpp
Normal file
426
libraries/gpu/src/gpu/GLBackendTexelFormat.cpp
Normal file
|
@ -0,0 +1,426 @@
|
|||
//
|
||||
// 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 "GLBackendShared.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLTexelFormat GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
||||
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
return texel;
|
||||
}
|
||||
|
||||
GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) {
|
||||
if (dstFormat != srcFormat) {
|
||||
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
|
||||
switch (dstFormat.getDimension()) {
|
||||
case gpu::SCALAR: {
|
||||
texel.format = GL_RED;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_R8;
|
||||
break;
|
||||
|
||||
case gpu::COMPRESSED_R:
|
||||
texel.internalFormat = GL_COMPRESSED_RED_RGTC1;
|
||||
break;
|
||||
|
||||
case gpu::DEPTH:
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||
break;
|
||||
case gpu::DEPTH_STENCIL:
|
||||
texel.type = GL_UNSIGNED_INT_24_8;
|
||||
texel.format = GL_DEPTH_STENCIL;
|
||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC2: {
|
||||
texel.format = GL_RG;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RG8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC3: {
|
||||
texel.format = GL_RGB;
|
||||
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::COMPRESSED_RGB:
|
||||
texel.internalFormat = GL_COMPRESSED_RGB;
|
||||
break;
|
||||
case gpu::COMPRESSED_SRGB:
|
||||
texel.internalFormat = GL_COMPRESSED_SRGB;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC4: {
|
||||
texel.format = GL_RGBA;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (srcFormat.getSemantic()) {
|
||||
case gpu::BGRA:
|
||||
case gpu::SBGRA:
|
||||
texel.format = GL_BGRA;
|
||||
break;
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
texel.internalFormat = GL_SRGB8;
|
||||
break;
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB8_ALPHA8;
|
||||
break;
|
||||
|
||||
case gpu::COMPRESSED_RGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_RGBA;
|
||||
break;
|
||||
case gpu::COMPRESSED_SRGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
|
||||
|
||||
break;
|
||||
|
||||
// FIXME: WE will want to support this later
|
||||
/*
|
||||
case gpu::COMPRESSED_BC3_RGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
break;
|
||||
case gpu::COMPRESSED_BC3_SRGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
|
||||
break;
|
||||
|
||||
case gpu::COMPRESSED_BC7_RGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
|
||||
break;
|
||||
case gpu::COMPRESSED_BC7_SRGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||
break;
|
||||
*/
|
||||
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
return texel;
|
||||
} else {
|
||||
GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
|
||||
switch (dstFormat.getDimension()) {
|
||||
case gpu::SCALAR: {
|
||||
texel.format = GL_RED;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::COMPRESSED_R: {
|
||||
texel.internalFormat = GL_COMPRESSED_RED_RGTC1;
|
||||
break;
|
||||
}
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_RED;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32: {
|
||||
texel.internalFormat = GL_R32UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT32: {
|
||||
texel.internalFormat = GL_R32I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT32: {
|
||||
texel.internalFormat = GL_R8;
|
||||
break;
|
||||
}
|
||||
case gpu::NINT32: {
|
||||
texel.internalFormat = GL_R8_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::FLOAT: {
|
||||
texel.internalFormat = GL_R32F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT16: {
|
||||
texel.internalFormat = GL_R16UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT16: {
|
||||
texel.internalFormat = GL_R16I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT16: {
|
||||
texel.internalFormat = GL_R16;
|
||||
break;
|
||||
}
|
||||
case gpu::NINT16: {
|
||||
texel.internalFormat = GL_R16_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::HALF: {
|
||||
texel.internalFormat = GL_R16F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT8: {
|
||||
texel.internalFormat = GL_R8UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT8: {
|
||||
texel.internalFormat = GL_R8I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT8: {
|
||||
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
|
||||
texel.internalFormat = GL_SLUMINANCE8;
|
||||
} else {
|
||||
texel.internalFormat = GL_R8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gpu::NINT8: {
|
||||
texel.internalFormat = GL_R8_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::NUM_TYPES: { // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case gpu::R11G11B10:
|
||||
texel.format = GL_RGB;
|
||||
// the type should be float
|
||||
texel.internalFormat = GL_R11F_G11F_B10F;
|
||||
break;
|
||||
|
||||
case gpu::DEPTH:
|
||||
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
case gpu::INT32:
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||
break;
|
||||
}
|
||||
case gpu::FLOAT: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT16:
|
||||
case gpu::INT16:
|
||||
case gpu::NUINT16:
|
||||
case gpu::NINT16:
|
||||
case gpu::HALF: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT16;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT8:
|
||||
case gpu::INT8:
|
||||
case gpu::NUINT8:
|
||||
case gpu::NINT8: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
||||
break;
|
||||
}
|
||||
case gpu::NUM_TYPES: { // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case gpu::DEPTH_STENCIL:
|
||||
texel.type = GL_UNSIGNED_INT_24_8;
|
||||
texel.format = GL_DEPTH_STENCIL;
|
||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC2: {
|
||||
texel.format = GL_RG;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RG8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC3: {
|
||||
texel.format = GL_RGB;
|
||||
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color
|
||||
break;
|
||||
case gpu::COMPRESSED_RGB:
|
||||
texel.internalFormat = GL_COMPRESSED_RGB;
|
||||
break;
|
||||
case gpu::COMPRESSED_SRGB:
|
||||
texel.internalFormat = GL_COMPRESSED_SRGB;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC4: {
|
||||
texel.format = GL_RGBA;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA32UI;
|
||||
break;
|
||||
case gpu::INT32:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA32I;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
texel.internalFormat = GL_RGBA32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA16UI;
|
||||
break;
|
||||
case gpu::INT16:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA16I;
|
||||
break;
|
||||
case gpu::NUINT16:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16;
|
||||
break;
|
||||
case gpu::NINT16:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16_SNORM;
|
||||
break;
|
||||
case gpu::HALF:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16F;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA8UI;
|
||||
break;
|
||||
case gpu::INT8:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA8I;
|
||||
break;
|
||||
case gpu::NUINT8:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case gpu::NINT8:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8_SNORM;
|
||||
break;
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
texel.format = GL_RGB;
|
||||
texel.internalFormat = GL_SRGB8;
|
||||
break;
|
||||
case gpu::SRGBA:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
|
||||
break;
|
||||
case gpu::COMPRESSED_RGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_RGBA;
|
||||
break;
|
||||
case gpu::COMPRESSED_SRGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
return texel;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@
|
|||
#include <QtCore/QThread>
|
||||
|
||||
#include "GLBackendShared.h"
|
||||
#include "GLTexelFormat.h"
|
||||
#include "GLBackendTextureTransfer.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
@ -49,49 +48,145 @@ const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = {
|
|||
|
||||
// Create the texture and allocate storage
|
||||
GLBackend::GLTexture::GLTexture(const Texture& texture) :
|
||||
_storageStamp(texture.getStamp()), _texture(allocateSingleTexture()),
|
||||
_target(gpuToGLTextureType(texture)), _size((GLuint)texture.getSize()), _gpuTexture(texture)
|
||||
_storageStamp(texture.getStamp()),
|
||||
_target(gpuToGLTextureType(texture)),
|
||||
_size(0),
|
||||
_virtualSize(0),
|
||||
_numLevels(texture.maxMip() + 1),
|
||||
_gpuTexture(texture)
|
||||
{
|
||||
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;
|
||||
|
||||
// updateSize();
|
||||
GLuint virtualSize = _gpuTexture.evalTotalSize();
|
||||
setVirtualSize(virtualSize);
|
||||
setSize(virtualSize);
|
||||
}
|
||||
|
||||
void GLBackend::GLTexture::createTexture() {
|
||||
_privateTexture = allocateSingleTexture();
|
||||
|
||||
GLsizei width = _gpuTexture.getWidth();
|
||||
GLsizei height = _gpuTexture.getHeight();
|
||||
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat());
|
||||
|
||||
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();
|
||||
|
||||
glBindTexture(_target, _privateTexture);
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
// Fixme: this usage of TexStorage doesn;t work wtih compressed texture, altuogh it should.
|
||||
// GO through the process of allocating the correct storage
|
||||
/* if (GLEW_VERSION_4_2 && !texture.getTexelFormat().isCompressed()) {
|
||||
glTexStorage2D(_target, _numLevels, texelFormat.internalFormat, width, height);
|
||||
(void)CHECK_GL_ERROR();
|
||||
} else*/
|
||||
{
|
||||
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _numLevels - 1);
|
||||
|
||||
// for (int l = 0; l < _numLevels; l++) {
|
||||
{ int l = 0;
|
||||
if (_gpuTexture.getType() == gpu::Texture::TEX_CUBE) {
|
||||
for (size_t face = 0; face < CUBE_NUM_FACES; face++) {
|
||||
glTexImage2D(CUBE_FACE_LAYOUT[face], l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL);
|
||||
}
|
||||
} else {
|
||||
glTexImage2D(_target, l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL);
|
||||
}
|
||||
levels = std::max(1, std::min(texture.maxMip() + 1, levels));
|
||||
width = std::max(1, (width / 2));
|
||||
height = std::max(1, (height / 2));
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
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();
|
||||
});
|
||||
syncSampler(_gpuTexture.getSampler(), _gpuTexture.getType(), this);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
|
||||
glBindTexture(_target, boundTex);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
GLBackend::GLTexture::~GLTexture() {
|
||||
if (_texture != 0) {
|
||||
glDeleteTextures(1, &_texture);
|
||||
if (_privateTexture != 0) {
|
||||
glDeleteTextures(1, &_privateTexture);
|
||||
}
|
||||
|
||||
Backend::updateTextureGPUMemoryUsage(_size, 0);
|
||||
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0);
|
||||
Backend::decrementTextureGPUCount();
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::GLTexture::setSize(GLuint size) {
|
||||
Backend::updateTextureGPUMemoryUsage(_size, size);
|
||||
_size = size;
|
||||
}
|
||||
|
||||
void GLBackend::GLTexture::setVirtualSize(GLuint size) {
|
||||
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, size);
|
||||
_virtualSize = size;
|
||||
}
|
||||
|
||||
void GLBackend::GLTexture::updateSize() {
|
||||
GLuint virtualSize = _gpuTexture.evalTotalSize();
|
||||
setVirtualSize(virtualSize);
|
||||
if (!_texture) {
|
||||
setSize(virtualSize);
|
||||
}
|
||||
|
||||
if (_gpuTexture.getTexelFormat().isCompressed()) {
|
||||
GLenum proxyType = GL_TEXTURE_2D;
|
||||
GLuint numFaces = 1;
|
||||
if (_gpuTexture.getType() == gpu::Texture::TEX_CUBE) {
|
||||
proxyType = CUBE_FACE_LAYOUT[0];
|
||||
numFaces = CUBE_NUM_FACES;
|
||||
}
|
||||
GLint gpuSize{ 0 };
|
||||
glGetTexLevelParameteriv(proxyType, 0, GL_TEXTURE_COMPRESSED, &gpuSize);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
if (gpuSize) {
|
||||
for (GLuint level = 0; level < _numLevels; level++) {
|
||||
GLint levelSize{ 0 };
|
||||
glGetTexLevelParameteriv(proxyType, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize);
|
||||
levelSize *= numFaces;
|
||||
|
||||
if (levelSize <= 0) {
|
||||
break;
|
||||
}
|
||||
gpuSize += levelSize;
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
setSize(gpuSize);
|
||||
} else {
|
||||
setSize(virtualSize);
|
||||
}
|
||||
|
||||
} else {
|
||||
setSize(virtualSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool GLBackend::GLTexture::isInvalid() const {
|
||||
return _storageStamp < _gpuTexture.getStamp();
|
||||
}
|
||||
|
@ -117,44 +212,25 @@ bool GLBackend::GLTexture::isReady() const {
|
|||
return Idle == syncState;
|
||||
}
|
||||
|
||||
//#define USE_PBO
|
||||
|
||||
// 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());
|
||||
#ifdef USE_PBO
|
||||
GLuint pixelBufferID;
|
||||
glGenBuffers(1, &pixelBufferID);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBufferID);
|
||||
//if (GLEW_VERSION_4_4) {
|
||||
// glBufferStorage(GL_PIXEL_UNPACK_BUFFER, mip->getSize(), nullptr, GL_STREAM_DRAW);
|
||||
//} else {
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, mip->getSize(), nullptr, GL_STREAM_DRAW);
|
||||
//}
|
||||
void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
|
||||
memcpy(mappedBuffer, mip->readData(), mip->getSize());
|
||||
//// use while PBO is still bound, assumes GL_TEXTURE_2D and offset 0
|
||||
glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, 0);
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glDeleteBuffers(1, &pixelBufferID);
|
||||
#else
|
||||
//glTexImage2D(target, 0, internalFormat, texture.getWidth(), texture.getHeight(), 0, texelFormat.format, texelFormat.type, bytes);
|
||||
glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData());
|
||||
glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData()); glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData());
|
||||
(void)CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Move content bits from the CPU to the GPU
|
||||
void GLBackend::GLTexture::transfer() const {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
qDebug() << "Transferring texture: " << _texture;
|
||||
//qDebug() << "Transferring texture: " << _privateTexture;
|
||||
// Need to update the content of the GPU object from the source sysmem of the texture
|
||||
if (_contentStamp >= _gpuTexture.getDataStamp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glBindTexture(_target, _texture);
|
||||
//_secretTexture
|
||||
glBindTexture(_target, _privateTexture);
|
||||
// glBindTexture(_target, _texture);
|
||||
// GO through the process of allocating the correct storage and/or update the content
|
||||
switch (_gpuTexture.getType()) {
|
||||
case Texture::TEX_2D:
|
||||
|
@ -186,6 +262,10 @@ void GLBackend::GLTexture::transfer() const {
|
|||
// Do any post-transfer operations that might be required on the main context / rendering thread
|
||||
void GLBackend::GLTexture::postTransfer() {
|
||||
setSyncState(GLTexture::Idle);
|
||||
|
||||
// The public gltexture becaomes available
|
||||
_texture = _privateTexture;
|
||||
|
||||
// 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:
|
||||
|
@ -204,7 +284,7 @@ void GLBackend::GLTexture::postTransfer() {
|
|||
}
|
||||
}
|
||||
|
||||
GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) {
|
||||
GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer, bool needTransfer) {
|
||||
const Texture& texture = *texturePointer;
|
||||
if (!texture.isDefined()) {
|
||||
// NO texture definition yet so let's avoid thinking
|
||||
|
@ -218,7 +298,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin
|
|||
}
|
||||
|
||||
// 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()) {
|
||||
|
@ -226,18 +306,23 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin
|
|||
object = new GLTexture(texture);
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
if (texture.getNumSlices() != 1) {
|
||||
// Object maybe doens't neet to be tranasferred after creation
|
||||
if (!needTransfer) {
|
||||
object->createTexture();
|
||||
object->_contentStamp = texturePointer->getDataStamp();
|
||||
object->postTransfer();
|
||||
return object;
|
||||
}
|
||||
|
||||
// Object might be outdated, if so, start the transfer
|
||||
// (outdated objects that are already in transfer will have reported 'true' for ready()
|
||||
if (object->isOutdated()) {
|
||||
Backend::incrementTextureGPUTransferCount();
|
||||
_textureTransferHelper->transferTexture(texturePointer);
|
||||
}
|
||||
|
||||
if (GLTexture::Transferred == object->getSyncState()) {
|
||||
Backend::decrementTextureGPUTransferCount();
|
||||
object->postTransfer();
|
||||
}
|
||||
|
||||
|
@ -338,7 +423,8 @@ void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) {
|
|||
return;
|
||||
}
|
||||
|
||||
GLTexture* object = GLBackend::syncGPUObject(resourceTexture);
|
||||
// DO not transfer the texture, this call is expected for rendering texture
|
||||
GLTexture* object = GLBackend::syncGPUObject(resourceTexture, false);
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -9,26 +9,12 @@
|
|||
#include "GLBackendTextureTransfer.h"
|
||||
|
||||
#include "GLBackendShared.h"
|
||||
#include "GLTexelFormat.h"
|
||||
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
|
||||
//#define FORCE_DRAW_AFTER_TRANSFER
|
||||
|
||||
#ifdef FORCE_DRAW_AFTER_TRANSFER
|
||||
|
||||
#include <gl/OglplusHelpers.h>
|
||||
|
||||
static ProgramPtr _program;
|
||||
static ProgramPtr _cubeProgram;
|
||||
static ShapeWrapperPtr _plane;
|
||||
static ShapeWrapperPtr _skybox;
|
||||
static BasicFramebufferWrapperPtr _framebuffer;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -50,30 +36,18 @@ GLTextureTransferHelper::GLTextureTransferHelper() {
|
|||
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();
|
||||
TextureTransferPackage package{ texturePointer, 0};
|
||||
object->setSyncState(GLBackend::GLTexture::Pending);
|
||||
queueItem(package);
|
||||
#else
|
||||
object->transfer();
|
||||
object->postTransfer();
|
||||
object->setSyncState(GLBackend::GLTexture::Transferred);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLTextureTransferHelper::setup() {
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
_canvas->makeCurrent();
|
||||
|
||||
#ifdef FORCE_DRAW_AFTER_TRANSFER
|
||||
_program = loadDefaultShader();
|
||||
_plane = loadPlane(_program);
|
||||
_cubeProgram = loadCubemapShader();
|
||||
_skybox = loadSkybox(_cubeProgram);
|
||||
_framebuffer = std::make_shared<BasicFramebufferWrapper>();
|
||||
_framebuffer->Init({ 100, 100 });
|
||||
_framebuffer->fbo.Bind(oglplus::FramebufferTarget::Draw);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -85,8 +59,6 @@ void GLTextureTransferHelper::shutdown() {
|
|||
|
||||
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) {
|
||||
|
@ -94,37 +66,17 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
|||
}
|
||||
|
||||
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
|
||||
object->createTexture();
|
||||
|
||||
object->transfer();
|
||||
|
||||
#ifdef FORCE_DRAW_AFTER_TRANSFER
|
||||
// Now force a draw using the texture
|
||||
try {
|
||||
switch (texturePointer->getType()) {
|
||||
case Texture::TEX_2D:
|
||||
_program->Use();
|
||||
_plane->Use();
|
||||
_plane->Draw();
|
||||
break;
|
||||
|
||||
case Texture::TEX_CUBE:
|
||||
_cubeProgram->Use();
|
||||
_skybox->Use();
|
||||
_skybox->Draw();
|
||||
break;
|
||||
|
||||
default:
|
||||
qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << texturePointer->getType() << " not supported";
|
||||
break;
|
||||
}
|
||||
} catch (const std::runtime_error& error) {
|
||||
qWarning() << "Failed to render texture on background thread: " << error.what();
|
||||
}
|
||||
#endif
|
||||
object->updateSize();
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,375 +0,0 @@
|
|||
//
|
||||
// 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 "GLBackendShared.h"
|
||||
|
||||
class GLTexelFormat {
|
||||
public:
|
||||
GLenum internalFormat;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
|
||||
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat) {
|
||||
return evalGLTexelFormat(dstFormat, dstFormat);
|
||||
}
|
||||
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat) {
|
||||
using namespace gpu;
|
||||
if (dstFormat != srcFormat) {
|
||||
GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
|
||||
switch (dstFormat.getDimension()) {
|
||||
case gpu::SCALAR: {
|
||||
texel.format = GL_RED;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_R8;
|
||||
break;
|
||||
case gpu::DEPTH:
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||
break;
|
||||
case gpu::DEPTH_STENCIL:
|
||||
texel.type = GL_UNSIGNED_INT_24_8;
|
||||
texel.format = GL_DEPTH_STENCIL;
|
||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC2: {
|
||||
texel.format = GL_RG;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RG8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC3: {
|
||||
texel.format = GL_RGB;
|
||||
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC4: {
|
||||
texel.format = GL_RGBA;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (srcFormat.getSemantic()) {
|
||||
case gpu::BGRA:
|
||||
case gpu::SBGRA:
|
||||
texel.format = GL_BGRA;
|
||||
break;
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
texel.internalFormat = GL_SRGB8;
|
||||
break;
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB8_ALPHA8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
return texel;
|
||||
} else {
|
||||
GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
|
||||
switch (dstFormat.getDimension()) {
|
||||
case gpu::SCALAR: {
|
||||
texel.format = GL_RED;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_R8;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32: {
|
||||
texel.internalFormat = GL_R32UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT32: {
|
||||
texel.internalFormat = GL_R32I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT32: {
|
||||
texel.internalFormat = GL_R8;
|
||||
break;
|
||||
}
|
||||
case gpu::NINT32: {
|
||||
texel.internalFormat = GL_R8_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::FLOAT: {
|
||||
texel.internalFormat = GL_R32F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT16: {
|
||||
texel.internalFormat = GL_R16UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT16: {
|
||||
texel.internalFormat = GL_R16I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT16: {
|
||||
texel.internalFormat = GL_R16;
|
||||
break;
|
||||
}
|
||||
case gpu::NINT16: {
|
||||
texel.internalFormat = GL_R16_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::HALF: {
|
||||
texel.internalFormat = GL_R16F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT8: {
|
||||
texel.internalFormat = GL_R8UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT8: {
|
||||
texel.internalFormat = GL_R8I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT8: {
|
||||
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
|
||||
texel.internalFormat = GL_SLUMINANCE8;
|
||||
} else {
|
||||
texel.internalFormat = GL_R8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gpu::NINT8: {
|
||||
texel.internalFormat = GL_R8_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::NUM_TYPES: { // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case gpu::R11G11B10:
|
||||
texel.format = GL_RGB;
|
||||
// the type should be float
|
||||
texel.internalFormat = GL_R11F_G11F_B10F;
|
||||
break;
|
||||
|
||||
case gpu::DEPTH:
|
||||
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
case gpu::INT32:
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||
break;
|
||||
}
|
||||
case gpu::FLOAT: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT16:
|
||||
case gpu::INT16:
|
||||
case gpu::NUINT16:
|
||||
case gpu::NINT16:
|
||||
case gpu::HALF: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT16;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT8:
|
||||
case gpu::INT8:
|
||||
case gpu::NUINT8:
|
||||
case gpu::NINT8: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
||||
break;
|
||||
}
|
||||
case gpu::NUM_TYPES: { // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case gpu::DEPTH_STENCIL:
|
||||
texel.type = GL_UNSIGNED_INT_24_8;
|
||||
texel.format = GL_DEPTH_STENCIL;
|
||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC2: {
|
||||
texel.format = GL_RG;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RG8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC3: {
|
||||
texel.format = GL_RGB;
|
||||
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC4: {
|
||||
texel.format = GL_RGBA;
|
||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA32UI;
|
||||
break;
|
||||
case gpu::INT32:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA32I;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
texel.internalFormat = GL_RGBA32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA16UI;
|
||||
break;
|
||||
case gpu::INT16:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA16I;
|
||||
break;
|
||||
case gpu::NUINT16:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16;
|
||||
break;
|
||||
case gpu::NINT16:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16_SNORM;
|
||||
break;
|
||||
case gpu::HALF:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16F;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA8UI;
|
||||
break;
|
||||
case gpu::INT8:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA8I;
|
||||
break;
|
||||
case gpu::NUINT8:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case gpu::NINT8:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8_SNORM;
|
||||
break;
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
texel.internalFormat = GL_SRGB8;
|
||||
break;
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
return texel;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -46,10 +46,17 @@ uint32_t Texture::getTextureGPUCount() {
|
|||
|
||||
Texture::Size Texture::getTextureGPUMemoryUsage() {
|
||||
return Context::getTextureGPUMemoryUsage();
|
||||
|
||||
}
|
||||
|
||||
uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6};
|
||||
Texture::Size Texture::getTextureGPUVirtualMemoryUsage() {
|
||||
return Context::getTextureGPUVirtualMemoryUsage();
|
||||
}
|
||||
|
||||
uint32_t Texture::getTextureGPUTransferCount() {
|
||||
return Context::getTextureGPUTransferCount();
|
||||
}
|
||||
|
||||
uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = { 1, 1, 1, 6 };
|
||||
|
||||
Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :
|
||||
_format(format),
|
||||
|
|
|
@ -146,6 +146,8 @@ public:
|
|||
static Size getTextureCPUMemoryUsage();
|
||||
static uint32_t getTextureGPUCount();
|
||||
static Size getTextureGPUMemoryUsage();
|
||||
static Size getTextureGPUVirtualMemoryUsage();
|
||||
static uint32_t getTextureGPUTransferCount();
|
||||
|
||||
class Usage {
|
||||
public:
|
||||
|
|
|
@ -417,7 +417,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur
|
|||
{
|
||||
_textures = Textures(MapChannel::NUM_MAP_CHANNELS);
|
||||
if (!material.albedoTexture.filename.isEmpty()) {
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
_albedoTransform = material.albedoTexture.transform;
|
||||
map->setTextureTransform(_albedoTransform);
|
||||
|
||||
|
@ -488,7 +488,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
|
|||
|
||||
if (!albedoName.isEmpty()) {
|
||||
auto url = textureMap.contains(albedoName) ? textureMap[albedoName].toUrl() : QUrl();
|
||||
auto map = fetchTextureMap(url, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
auto map = fetchTextureMap(url, ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||
map->setTextureTransform(_albedoTransform);
|
||||
// when reassigning the albedo texture we also check for the alpha channel used as opacity
|
||||
map->setUseAlphaChannel(true);
|
||||
|
@ -497,7 +497,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
|
|||
|
||||
if (!normalName.isEmpty()) {
|
||||
auto url = textureMap.contains(normalName) ? textureMap[normalName].toUrl() : QUrl();
|
||||
auto map = fetchTextureMap(url, DEFAULT_TEXTURE, MapChannel::NORMAL_MAP);
|
||||
auto map = fetchTextureMap(url, NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
|
||||
setTextureMap(MapChannel::NORMAL_MAP, map);
|
||||
}
|
||||
|
||||
|
|
|
@ -203,6 +203,18 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
|
|||
|
||||
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
||||
switch (_type) {
|
||||
case ALBEDO_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureUsage::createAlbedoTextureFromImage);
|
||||
break;
|
||||
}
|
||||
case EMISSIVE_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureUsage::createEmissiveTextureFromImage);
|
||||
break;
|
||||
}
|
||||
case LIGHTMAP_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureUsage::createLightmapTextureFromImage);
|
||||
break;
|
||||
}
|
||||
case CUBE_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureUsage::createCubeTextureFromImage);
|
||||
break;
|
||||
|
@ -232,7 +244,6 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
|||
break;
|
||||
}
|
||||
case DEFAULT_TEXTURE:
|
||||
case EMISSIVE_TEXTURE:
|
||||
default: {
|
||||
return TextureLoaderFunc(model::TextureUsage::create2DTextureFromImage);
|
||||
break;
|
||||
|
|
|
@ -31,6 +31,7 @@ typedef QSharedPointer<NetworkTexture> NetworkTexturePointer;
|
|||
|
||||
enum TextureType {
|
||||
DEFAULT_TEXTURE,
|
||||
ALBEDO_TEXTURE,
|
||||
NORMAL_TEXTURE,
|
||||
BUMP_TEXTURE,
|
||||
SPECULAR_TEXTURE,
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
using namespace model;
|
||||
using namespace gpu;
|
||||
|
||||
// FIXME: Declare this to enable compression
|
||||
//#define COMPRESS_TEXTURES
|
||||
|
||||
|
||||
void TextureMap::setTextureSource(TextureSourcePointer& textureSource) {
|
||||
_textureSource = textureSource;
|
||||
|
@ -49,12 +52,10 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
|
|||
_lightmapOffsetScale.y = scale;
|
||||
}
|
||||
|
||||
|
||||
// FIXME why is this in the model library? Move to GPU or GPU_GL
|
||||
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
|
||||
QImage image = srcImage;
|
||||
bool validAlpha = false;
|
||||
bool alphaAsMask = true;
|
||||
validAlpha = false;
|
||||
alphaAsMask = true;
|
||||
const uint8 OPAQUE_ALPHA = 255;
|
||||
const uint8 TRANSPARENT_ALPHA = 0;
|
||||
if (image.hasAlphaChannel()) {
|
||||
|
@ -63,7 +64,7 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
|
|||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
|
||||
// Actual alpha channel? create the histogram
|
||||
for (int y = 0; y < image.height(); ++y) {
|
||||
const QRgb* data = reinterpret_cast<const QRgb*>(image.constScanLine(y));
|
||||
|
@ -83,23 +84,77 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
|
|||
|
||||
alphaAsMask = ((numTranslucents / (double)totalNumPixels) < 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!validAlpha && image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void TextureUsage::defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip,
|
||||
const QImage& image, bool isLinear, bool doCompress) {
|
||||
|
||||
#ifdef COMPRESS_TEXTURES
|
||||
#else
|
||||
doCompress = false;
|
||||
#endif
|
||||
|
||||
if (image.hasAlphaChannel()) {
|
||||
gpu::Semantic gpuSemantic;
|
||||
gpu::Semantic mipSemantic;
|
||||
if (isLinear) {
|
||||
mipSemantic = gpu::SBGRA;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_SRGBA;
|
||||
} else {
|
||||
gpuSemantic = gpu::SRGBA;
|
||||
}
|
||||
} else {
|
||||
mipSemantic = gpu::BGRA;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_RGBA;
|
||||
} else {
|
||||
gpuSemantic = gpu::RGBA;
|
||||
}
|
||||
}
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpuSemantic);
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, mipSemantic);
|
||||
} else {
|
||||
gpu::Semantic gpuSemantic;
|
||||
gpu::Semantic mipSemantic;
|
||||
if (isLinear) {
|
||||
mipSemantic = gpu::SRGB;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_SRGB;
|
||||
} else {
|
||||
gpuSemantic = gpu::SRGB;
|
||||
}
|
||||
} else {
|
||||
mipSemantic = gpu::RGB;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_RGB;
|
||||
} else {
|
||||
gpuSemantic = gpu::RGB;
|
||||
}
|
||||
}
|
||||
formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic);
|
||||
formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic);
|
||||
}
|
||||
}
|
||||
|
||||
gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips) {
|
||||
bool validAlpha = false;
|
||||
bool alphaAsMask = true;
|
||||
QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask);
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
gpu::Element formatGPU;
|
||||
gpu::Element formatMip;
|
||||
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
|
||||
|
@ -113,40 +168,46 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
|
|||
theTexture->setUsage(usage.build());
|
||||
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
|
||||
// FIXME queue for transfer to GPU and block on completion
|
||||
|
||||
if (generateMips) {
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
||||
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return process2DTextureColorFromImage(srcImage, true, false, true);
|
||||
}
|
||||
|
||||
|
||||
gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||
}
|
||||
|
||||
gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||
}
|
||||
|
||||
gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||
}
|
||||
|
||||
|
||||
gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
} else {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||
|
||||
bool isLinearRGB = true;
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
|
@ -179,7 +240,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
|
|||
const double pStrength = 2.0;
|
||||
int width = image.width();
|
||||
int height = image.height();
|
||||
QImage result(width, height, image.format());
|
||||
QImage result(width, height, QImage::Format_RGB888);
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
const int iNextClamped = clampPixelCoordinate(i + 1, width - 1);
|
||||
|
@ -227,23 +288,16 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
|
|||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
||||
|
@ -263,8 +317,11 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
|
|||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
#ifdef COMPRESS_TEXTURES
|
||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R);
|
||||
#else
|
||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||
#endif
|
||||
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
|
@ -297,9 +354,13 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
|
|||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
#ifdef COMPRESS_TEXTURES
|
||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R);
|
||||
#else
|
||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||
#endif
|
||||
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
|
@ -327,7 +388,11 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag
|
|||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
#ifdef COMPRESS_TEXTURES
|
||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R);
|
||||
#else
|
||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||
#endif
|
||||
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
|
@ -372,315 +437,181 @@ public:
|
|||
_faceYNeg(fYN),
|
||||
_faceZPos(fZP),
|
||||
_faceZNeg(fZN) {}
|
||||
|
||||
|
||||
static const CubeLayout CUBEMAP_LAYOUTS[];
|
||||
static const int NUM_CUBEMAP_LAYOUTS;
|
||||
|
||||
static int findLayout(int width, int height) {
|
||||
// Find the layout of the cubemap in the 2D image
|
||||
int foundLayout = -1;
|
||||
for (int i = 0; i < NUM_CUBEMAP_LAYOUTS; i++) {
|
||||
if ((height * CUBEMAP_LAYOUTS[i]._widthRatio) == (width * CUBEMAP_LAYOUTS[i]._heightRatio)) {
|
||||
foundLayout = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return foundLayout;
|
||||
}
|
||||
};
|
||||
|
||||
gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
||||
|
||||
qCDebug(modelLog) << "Cube map size:" << QString(srcImageName.c_str()) << image.width() << image.height();
|
||||
|
||||
int opaquePixels = 0;
|
||||
int translucentPixels = 0;
|
||||
//bool isTransparent = false;
|
||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
}
|
||||
}
|
||||
if (imageArea > 0) {
|
||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
||||
}
|
||||
} else {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// check for translucency/false transparency
|
||||
// int opaquePixels = 0;
|
||||
// int translucentPixels = 0;
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
int alpha = qAlpha(rgb);
|
||||
alphaTotal += alpha;
|
||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
||||
opaquePixels++;
|
||||
} else if (alpha != 0) {
|
||||
translucentPixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opaquePixels == imageArea) {
|
||||
qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str());
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
averageColor = QColor(redTotal / imageArea,
|
||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
||||
|
||||
//isTransparent = (translucentPixels >= imageArea / 2);
|
||||
const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = {
|
||||
// Here is the expected layout for the faces in an image with the 1/6 aspect ratio:
|
||||
//
|
||||
// WIDTH
|
||||
// <------>
|
||||
// ^ +------+
|
||||
// | | |
|
||||
// | | +X |
|
||||
// | | |
|
||||
// H +------+
|
||||
// E | |
|
||||
// I | -X |
|
||||
// G | |
|
||||
// H +------+
|
||||
// T | |
|
||||
// | | +Y |
|
||||
// | | |
|
||||
// | +------+
|
||||
// | | |
|
||||
// | | -Y |
|
||||
// | | |
|
||||
// H +------+
|
||||
// E | |
|
||||
// I | +Z |
|
||||
// G | |
|
||||
// H +------+
|
||||
// T | |
|
||||
// | | -Z |
|
||||
// | | |
|
||||
// V +------+
|
||||
//
|
||||
// FaceWidth = width = height / 6
|
||||
{ 1, 6,
|
||||
{ 0, 0, true, false },
|
||||
{ 0, 1, true, false },
|
||||
{ 0, 2, false, true },
|
||||
{ 0, 3, false, true },
|
||||
{ 0, 4, true, false },
|
||||
{ 0, 5, true, false }
|
||||
},
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 3/4 aspect ratio:
|
||||
//
|
||||
// <-----------WIDTH----------->
|
||||
// ^ +------+------+------+------+
|
||||
// | | | | | |
|
||||
// | | | +Y | | |
|
||||
// | | | | | |
|
||||
// H +------+------+------+------+
|
||||
// E | | | | |
|
||||
// I | -X | -Z | +X | +Z |
|
||||
// G | | | | |
|
||||
// H +------+------+------+------+
|
||||
// T | | | | |
|
||||
// | | | -Y | | |
|
||||
// | | | | | |
|
||||
// V +------+------+------+------+
|
||||
//
|
||||
// FaceWidth = width / 4 = height / 3
|
||||
{ 4, 3,
|
||||
{ 2, 1, true, false },
|
||||
{ 0, 1, true, false },
|
||||
{ 1, 0, false, true },
|
||||
{ 1, 2, false, true },
|
||||
{ 3, 1, true, false },
|
||||
{ 1, 1, true, false }
|
||||
},
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 4/3 aspect ratio:
|
||||
//
|
||||
// <-------WIDTH-------->
|
||||
// ^ +------+------+------+
|
||||
// | | | | |
|
||||
// | | | +Y | |
|
||||
// | | | | |
|
||||
// H +------+------+------+
|
||||
// E | | | |
|
||||
// I | -X | -Z | +X |
|
||||
// G | | | |
|
||||
// H +------+------+------+
|
||||
// T | | | |
|
||||
// | | | -Y | |
|
||||
// | | | | |
|
||||
// | +------+------+------+
|
||||
// | | | | |
|
||||
// | | | +Z! | | <+Z is upside down!
|
||||
// | | | | |
|
||||
// V +------+------+------+
|
||||
//
|
||||
// FaceWidth = width / 3 = height / 4
|
||||
{ 3, 4,
|
||||
{ 2, 1, true, false },
|
||||
{ 0, 1, true, false },
|
||||
{ 1, 0, false, true },
|
||||
{ 1, 2, false, true },
|
||||
{ 1, 3, false, true },
|
||||
{ 1, 1, true, false }
|
||||
}
|
||||
|
||||
};
|
||||
const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||
|
||||
gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) {
|
||||
|
||||
bool validAlpha = false;
|
||||
bool alphaAsMask = true;
|
||||
QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask);
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
gpu::Element formatGPU;
|
||||
gpu::Element formatMip;
|
||||
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
|
||||
|
||||
// Find the layout of the cubemap in the 2D image
|
||||
int foundLayout = CubeLayout::findLayout(image.width(), image.height());
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
std::vector<QImage> faces;
|
||||
// If found, go extract the faces as separate images
|
||||
if (foundLayout >= 0) {
|
||||
auto& layout = CubeLayout::CUBEMAP_LAYOUTS[foundLayout];
|
||||
int faceWidth = image.width() / layout._widthRatio;
|
||||
|
||||
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
||||
} else {
|
||||
qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
const CubeLayout CUBEMAP_LAYOUTS[] = {
|
||||
// Here is the expected layout for the faces in an image with the 1/6 aspect ratio:
|
||||
//
|
||||
// WIDTH
|
||||
// <------>
|
||||
// ^ +------+
|
||||
// | | |
|
||||
// | | +X |
|
||||
// | | |
|
||||
// H +------+
|
||||
// E | |
|
||||
// I | -X |
|
||||
// G | |
|
||||
// H +------+
|
||||
// T | |
|
||||
// | | +Y |
|
||||
// | | |
|
||||
// | +------+
|
||||
// | | |
|
||||
// | | -Y |
|
||||
// | | |
|
||||
// H +------+
|
||||
// E | |
|
||||
// I | +Z |
|
||||
// G | |
|
||||
// H +------+
|
||||
// T | |
|
||||
// | | -Z |
|
||||
// | | |
|
||||
// V +------+
|
||||
//
|
||||
// FaceWidth = width = height / 6
|
||||
{ 1, 6,
|
||||
{0, 0, true, false},
|
||||
{0, 1, true, false},
|
||||
{0, 2, false, true},
|
||||
{0, 3, false, true},
|
||||
{0, 4, true, false},
|
||||
{0, 5, true, false}
|
||||
},
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 3/4 aspect ratio:
|
||||
//
|
||||
// <-----------WIDTH----------->
|
||||
// ^ +------+------+------+------+
|
||||
// | | | | | |
|
||||
// | | | +Y | | |
|
||||
// | | | | | |
|
||||
// H +------+------+------+------+
|
||||
// E | | | | |
|
||||
// I | -X | -Z | +X | +Z |
|
||||
// G | | | | |
|
||||
// H +------+------+------+------+
|
||||
// T | | | | |
|
||||
// | | | -Y | | |
|
||||
// | | | | | |
|
||||
// V +------+------+------+------+
|
||||
//
|
||||
// FaceWidth = width / 4 = height / 3
|
||||
{ 4, 3,
|
||||
{2, 1, true, false},
|
||||
{0, 1, true, false},
|
||||
{1, 0, false, true},
|
||||
{1, 2, false, true},
|
||||
{3, 1, true, false},
|
||||
{1, 1, true, false}
|
||||
},
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 4/3 aspect ratio:
|
||||
//
|
||||
// <-------WIDTH-------->
|
||||
// ^ +------+------+------+
|
||||
// | | | | |
|
||||
// | | | +Y | |
|
||||
// | | | | |
|
||||
// H +------+------+------+
|
||||
// E | | | |
|
||||
// I | -X | -Z | +X |
|
||||
// G | | | |
|
||||
// H +------+------+------+
|
||||
// T | | | |
|
||||
// | | | -Y | |
|
||||
// | | | | |
|
||||
// | +------+------+------+
|
||||
// | | | | |
|
||||
// | | | +Z! | | <+Z is upside down!
|
||||
// | | | | |
|
||||
// V +------+------+------+
|
||||
//
|
||||
// FaceWidth = width / 3 = height / 4
|
||||
{ 3, 4,
|
||||
{2, 1, true, false},
|
||||
{0, 1, true, false},
|
||||
{1, 0, false, true},
|
||||
{1, 2, false, true},
|
||||
{1, 3, false, true},
|
||||
{1, 1, true, false}
|
||||
}
|
||||
};
|
||||
const int NUM_CUBEMAP_LAYOUTS = sizeof(CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||
|
||||
// Find the layout of the cubemap in the 2D image
|
||||
int foundLayout = -1;
|
||||
for (int i = 0; i < NUM_CUBEMAP_LAYOUTS; i++) {
|
||||
if ((image.height() * CUBEMAP_LAYOUTS[i]._widthRatio) == (image.width() * CUBEMAP_LAYOUTS[i]._heightRatio)) {
|
||||
foundLayout = i;
|
||||
break;
|
||||
}
|
||||
// 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));
|
||||
int f = 0;
|
||||
for (auto& face : faces) {
|
||||
theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f);
|
||||
f++;
|
||||
}
|
||||
|
||||
std::vector<QImage> faces;
|
||||
// If found, go extract the faces as separate images
|
||||
if (foundLayout >= 0) {
|
||||
auto& layout = CUBEMAP_LAYOUTS[foundLayout];
|
||||
int faceWidth = image.width() / layout._widthRatio;
|
||||
|
||||
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
||||
} else {
|
||||
qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
if (generateMips) {
|
||||
theTexture->autoGenerateMips(-1);
|
||||
int f = 0;
|
||||
for (auto& face : faces) {
|
||||
theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f);
|
||||
f++;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate irradiance while we are at it
|
||||
// Generate irradiance while we are at it
|
||||
if (generateIrradiance) {
|
||||
theTexture->generateIrradiance();
|
||||
}
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
||||
|
||||
gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
||||
int opaquePixels = 0;
|
||||
int translucentPixels = 0;
|
||||
//bool isTransparent = false;
|
||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
}
|
||||
}
|
||||
if (imageArea > 0) {
|
||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
||||
}
|
||||
} else {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// check for translucency/false transparency
|
||||
// int opaquePixels = 0;
|
||||
// int translucentPixels = 0;
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
int alpha = qAlpha(rgb);
|
||||
alphaTotal += alpha;
|
||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
||||
opaquePixels++;
|
||||
} else if (alpha != 0) {
|
||||
translucentPixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opaquePixels == imageArea) {
|
||||
qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str());
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
averageColor = QColor(redTotal / imageArea,
|
||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
||||
|
||||
//isTransparent = (translucentPixels >= imageArea / 2);
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
||||
gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return processCubeTextureColorFromImage(srcImage, srcImageName, false, true, true, true);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
int _environmentUsage = 0;
|
||||
|
||||
static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createAlbedoTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createEmissiveTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createNormalTextureFromNormalImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createRoughnessTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
|
@ -40,6 +42,13 @@ public:
|
|||
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
|
||||
|
||||
static const QImage process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask);
|
||||
static void defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip,
|
||||
const QImage& srcImage, bool isLinear, bool doCompress);
|
||||
static gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips);
|
||||
static gpu::Texture* processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte
|
|||
config->textureGPUCount = gpu::Texture::getTextureGPUCount();
|
||||
config->textureCPUMemoryUsage = gpu::Texture::getTextureCPUMemoryUsage();
|
||||
config->textureGPUMemoryUsage = gpu::Texture::getTextureGPUMemoryUsage();
|
||||
config->textureGPUVirtualMemoryUsage = gpu::Texture::getTextureGPUVirtualMemoryUsage();
|
||||
config->textureGPUTransferCount = gpu::Texture::getTextureGPUTransferCount();
|
||||
|
||||
gpu::ContextStats gpuStats(_gpuStats);
|
||||
renderContext->args->_context->getStats(_gpuStats);
|
||||
|
@ -45,6 +47,7 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte
|
|||
|
||||
config->frameTextureCount = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded;
|
||||
config->frameTextureRate = config->frameTextureCount * frequency;
|
||||
config->frameTextureMemoryUsage = _gpuStats._RSAmountTextureMemoryBounded - gpuStats._RSAmountTextureMemoryBounded;
|
||||
|
||||
config->emitDirty();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ namespace render {
|
|||
Q_PROPERTY(quint32 textureGPUCount MEMBER textureGPUCount NOTIFY dirty)
|
||||
Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty)
|
||||
Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage 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 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty)
|
||||
|
@ -43,7 +45,7 @@ namespace render {
|
|||
|
||||
Q_PROPERTY(quint32 frameTextureCount MEMBER frameTextureCount NOTIFY dirty)
|
||||
Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty)
|
||||
|
||||
Q_PROPERTY(quint32 frameTextureMemoryUsage MEMBER frameTextureMemoryUsage NOTIFY dirty)
|
||||
|
||||
public:
|
||||
EngineStatsConfig() : Job::Config(true) {}
|
||||
|
@ -57,6 +59,8 @@ namespace render {
|
|||
quint32 textureGPUCount{ 0 };
|
||||
qint64 textureCPUMemoryUsage{ 0 };
|
||||
qint64 textureGPUMemoryUsage{ 0 };
|
||||
qint64 textureGPUVirtualMemoryUsage{ 0 };
|
||||
quint32 textureGPUTransferCount{ 0 };
|
||||
|
||||
quint32 frameAPIDrawcallCount{ 0 };
|
||||
quint32 frameDrawcallCount{ 0 };
|
||||
|
@ -67,6 +71,7 @@ namespace render {
|
|||
|
||||
quint32 frameTextureCount{ 0 };
|
||||
quint32 frameTextureRate{ 0 };
|
||||
qint64 frameTextureMemoryUsage{ 0 };
|
||||
|
||||
void emitDirty() { emit dirty(); }
|
||||
|
||||
|
|
Loading…
Reference in a new issue