mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-07 19:23:04 +02:00
Fixed compression when convolving
This commit is contained in:
parent
cef9e454d5
commit
5f6f178438
4 changed files with 216 additions and 115 deletions
|
@ -16,6 +16,9 @@
|
|||
|
||||
#include "RandomAndNoise.h"
|
||||
#include "Image.h"
|
||||
#include "ImageLogging.h"
|
||||
|
||||
#include <nvtt/nvtt.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265359
|
||||
|
@ -57,11 +60,16 @@ static const glm::vec3 FACE_NORMALS[24] = {
|
|||
};
|
||||
|
||||
struct CubeFaceMip {
|
||||
|
||||
CubeFaceMip(gpu::uint16 level, const CubeMap* cubemap) {
|
||||
_dims = cubemap->getMipDimensions(level);
|
||||
_lineStride = _dims.x + 2;
|
||||
}
|
||||
|
||||
CubeFaceMip(const CubeFaceMip& other) : _dims(other._dims), _lineStride(other._lineStride) {
|
||||
|
||||
}
|
||||
|
||||
gpu::Vec2i _dims;
|
||||
int _lineStride;
|
||||
};
|
||||
|
@ -101,10 +109,13 @@ private:
|
|||
class CubeMap::Mip : public CubeFaceMip {
|
||||
public:
|
||||
|
||||
Mip(gpu::uint16 level, CubeMap* cubemap) :
|
||||
explicit Mip(gpu::uint16 level, CubeMap* cubemap) :
|
||||
CubeFaceMip(level, cubemap), _faces(cubemap->_mips[level]) {
|
||||
}
|
||||
|
||||
Mip(const Mip& other) : CubeFaceMip(other), _faces(other._faces) {
|
||||
}
|
||||
|
||||
void applySeams() {
|
||||
// Copy edge rows and columns from neighbouring faces to fix seam filtering issues
|
||||
seamColumnAndRow(gpu::Texture::CUBE_FACE_TOP_POS_Y, _dims.x, gpu::Texture::CUBE_FACE_RIGHT_POS_X, -1, -1);
|
||||
|
@ -139,6 +150,14 @@ private:
|
|||
|
||||
Faces& _faces;
|
||||
|
||||
inline static void copy(const glm::vec4* srcFirst, const glm::vec4* srcLast, int srcStride, glm::vec4* dstBegin, int dstStride) {
|
||||
while (srcFirst <= srcLast) {
|
||||
*dstBegin = *srcFirst;
|
||||
srcFirst += srcStride;
|
||||
dstBegin += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
static std::pair<int, int> getSrcAndDst(int dim, int value) {
|
||||
int src;
|
||||
int dst;
|
||||
|
@ -177,14 +196,6 @@ private:
|
|||
copyRowToRow(face1, coords1.first, face0, coords0.second, inc);
|
||||
}
|
||||
|
||||
inline static void copy(const glm::vec4* srcFirst, const glm::vec4* srcLast, int srcStride, glm::vec4* dstBegin, int dstStride) {
|
||||
while (srcFirst <= srcLast) {
|
||||
*dstBegin = *srcFirst;
|
||||
srcFirst += srcStride;
|
||||
dstBegin += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
void copyColumnToColumn(int srcFace, int srcCol, int dstFace, int dstCol, const int dstInc) {
|
||||
const auto lastOffset = _lineStride * (_dims.y - 1);
|
||||
auto srcFirst = _faces[srcFace].data() + srcCol + _lineStride;
|
||||
|
@ -254,33 +265,83 @@ CubeMap::CubeMap(int width, int height, int mipCount) {
|
|||
reset(width, height, mipCount);
|
||||
}
|
||||
|
||||
CubeMap::CubeMap(gpu::Texture* texture, const std::atomic<bool>& abortProcessing) {
|
||||
reset(texture->getWidth(), texture->getHeight(), texture->getNumMips());
|
||||
struct CubeMap::MipMapOutputHandler : public nvtt::OutputHandler {
|
||||
MipMapOutputHandler(CubeMap* cube) : _cubemap(cube) {}
|
||||
|
||||
void beginImage(int size, int width, int height, int depth, int face, int miplevel) override {
|
||||
_data = _cubemap->editFace(miplevel, face);
|
||||
_current = _data;
|
||||
}
|
||||
|
||||
bool writeData(const void* data, int size) override {
|
||||
assert((size % sizeof(glm::vec4)) == 0);
|
||||
memcpy(_current, data, size);
|
||||
_current += size / sizeof(glm::vec4);
|
||||
return true;
|
||||
}
|
||||
|
||||
void endImage() override {
|
||||
_data = nullptr;
|
||||
_current = nullptr;
|
||||
}
|
||||
|
||||
CubeMap* _cubemap{ nullptr };
|
||||
glm::vec4* _data{ nullptr };
|
||||
glm::vec4* _current{ nullptr };
|
||||
};
|
||||
|
||||
CubeMap::CubeMap(const std::vector<QImage>& faces, gpu::Element srcTextureFormat, int mipCount, const std::atomic<bool>& abortProcessing) {
|
||||
reset(faces.front().width(), faces.front().height(), mipCount);
|
||||
|
||||
const auto srcTextureFormat = texture->getTexelFormat();
|
||||
int face;
|
||||
|
||||
for (gpu::uint16 mipLevel = 0; mipLevel < texture->getNumMips(); ++mipLevel) {
|
||||
auto mipDims = texture->evalMipDimensions(mipLevel);
|
||||
auto srcLineStride = (int) (sizeof(gpu::uint32)*mipDims.x);
|
||||
auto dstLineStride = getFaceLineStride(mipLevel);
|
||||
|
||||
for (face = 0; face < 6; face++) {
|
||||
auto sourcePixels = texture->accessStoredMipFace(mipLevel, face)->data();
|
||||
auto destPixels = editFace(mipLevel, face);
|
||||
|
||||
convertToFloat(sourcePixels, mipDims.x, mipDims.y, srcLineStride, srcTextureFormat, destPixels, dstLineStride);
|
||||
if (abortProcessing.load()) {
|
||||
return;
|
||||
}
|
||||
struct MipMapErrorHandler : public nvtt::ErrorHandler {
|
||||
virtual void error(nvtt::Error e) override {
|
||||
qCWarning(imagelogging) << "Texture mip map creation error:" << nvtt::errorString(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Compute mips
|
||||
for (face = 0; face < 6; face++) {
|
||||
auto sourcePixels = faces[face].bits();
|
||||
auto floatPixels = editFace(0, face);
|
||||
|
||||
convertToFloat(sourcePixels, _width, _height, faces[face].bytesPerLine(), srcTextureFormat, floatPixels, _width);
|
||||
|
||||
nvtt::Surface surface;
|
||||
surface.setImage(nvtt::InputFormat_RGBA_32F, _width, _height, 1, floatPixels);
|
||||
surface.setAlphaMode(nvtt::AlphaMode_None);
|
||||
surface.setWrapMode(nvtt::WrapMode_Clamp);
|
||||
|
||||
auto mipLevel = 0;
|
||||
copyFace(_width, _height, reinterpret_cast<const glm::vec4*>(surface.data()), surface.width(), editFace(0, face), getFaceLineStride(0));
|
||||
|
||||
while (surface.canMakeNextMipmap() && !abortProcessing.load()) {
|
||||
surface.buildNextMipmap(nvtt::MipmapFilter_Box);
|
||||
mipLevel++;
|
||||
|
||||
copyFace(surface.width(), surface.height(), reinterpret_cast<const glm::vec4*>(surface.data()), surface.width(), editFace(mipLevel, face), getFaceLineStride(mipLevel));
|
||||
}
|
||||
}
|
||||
|
||||
if (abortProcessing.load()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (gpu::uint16 mipLevel = 0; mipLevel < mipCount; ++mipLevel) {
|
||||
Mip mip(mipLevel, this);
|
||||
|
||||
mip.applySeams();
|
||||
}
|
||||
}
|
||||
|
||||
void CubeMap::copyFace(int width, int height, const glm::vec4* source, int srcLineStride, glm::vec4* dest, int dstLineStride) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
std::copy(source, source + width, dest);
|
||||
source += srcLineStride;
|
||||
dest += dstLineStride;
|
||||
}
|
||||
}
|
||||
|
||||
void CubeMap::reset(int width, int height, int mipCount) {
|
||||
assert(mipCount >0 && _width > 0 && _height > 0);
|
||||
_width = width;
|
||||
|
@ -301,29 +362,45 @@ void CubeMap::reset(int width, int height, int mipCount) {
|
|||
void CubeMap::copyTo(gpu::Texture* texture, const std::atomic<bool>& abortProcessing) const {
|
||||
assert(_width == texture->getWidth() && _height == texture->getHeight() && texture->getNumMips() == _mips.size());
|
||||
|
||||
// Convert all mip data back from float
|
||||
unsigned char* convertedPixels = new unsigned char[_width * _height * sizeof(gpu::uint32)];
|
||||
const auto textureFormat = texture->getTexelFormat();
|
||||
struct CompressionpErrorHandler : public nvtt::ErrorHandler {
|
||||
virtual void error(nvtt::Error e) override {
|
||||
qCWarning(imagelogging) << "Texture compression error:" << nvtt::errorString(e);
|
||||
}
|
||||
};
|
||||
|
||||
for (gpu::uint16 mipLevel = 0; mipLevel < texture->getNumMips(); ++mipLevel) {
|
||||
auto mipDims = texture->evalMipDimensions(mipLevel);
|
||||
auto mipSize = texture->evalMipFaceSize(mipLevel);
|
||||
auto srcLineStride = getFaceLineStride(mipLevel);
|
||||
auto dstLineStride = (int)(sizeof(gpu::uint32)*mipDims.x);
|
||||
CompressionpErrorHandler errorHandler;
|
||||
nvtt::OutputOptions outputOptions;
|
||||
outputOptions.setOutputHeader(false);
|
||||
outputOptions.setErrorHandler(&errorHandler);
|
||||
|
||||
for (auto face = 0; face < 6; face++) {
|
||||
auto srcPixels = getFace(mipLevel, face);
|
||||
nvtt::Surface surface;
|
||||
surface.setAlphaMode(nvtt::AlphaMode_None);
|
||||
surface.setWrapMode(nvtt::WrapMode_Clamp);
|
||||
|
||||
convertFromFloat(convertedPixels, mipDims.x, mipDims.y, dstLineStride, textureFormat, srcPixels, srcLineStride);
|
||||
texture->assignStoredMipFace(mipLevel, face, mipSize, convertedPixels);
|
||||
if (abortProcessing.load()) {
|
||||
delete[] convertedPixels;
|
||||
return;
|
||||
}
|
||||
glm::vec4* packedPixels = new glm::vec4[_width * _height];
|
||||
for (int face = 0; face < 6; face++) {
|
||||
nvtt::CompressionOptions compressionOptions;
|
||||
std::unique_ptr<nvtt::OutputHandler> outputHandler{ getNVTTCompressionOutputHandler(texture, face, compressionOptions) };
|
||||
|
||||
outputOptions.setOutputHandler(outputHandler.get());
|
||||
|
||||
SequentialTaskDispatcher dispatcher(abortProcessing);
|
||||
nvtt::Context context;
|
||||
context.setTaskDispatcher(&dispatcher);
|
||||
|
||||
for (gpu::uint16 mipLevel = 0; mipLevel < _mips.size() && !abortProcessing.load(); mipLevel++) {
|
||||
auto mipDims = getMipDimensions(mipLevel);
|
||||
|
||||
copyFace(mipDims.x, mipDims.y, getFace(mipLevel, face), getFaceLineStride(mipLevel), packedPixels, mipDims.x);
|
||||
surface.setImage(nvtt::InputFormat_RGBA_32F, mipDims.x, mipDims.y, 1, packedPixels);
|
||||
context.compress(surface, face, mipLevel, compressionOptions, outputOptions);
|
||||
}
|
||||
|
||||
if (abortProcessing.load()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] convertedPixels;
|
||||
delete[] packedPixels;
|
||||
}
|
||||
|
||||
void CubeMap::getFaceUV(const glm::vec3& dir, int* index, glm::vec2* uv) {
|
||||
|
|
|
@ -18,13 +18,15 @@
|
|||
#include <array>
|
||||
#include <atomic>
|
||||
|
||||
#include <QImage>
|
||||
|
||||
namespace image {
|
||||
|
||||
class CubeMap {
|
||||
public:
|
||||
|
||||
CubeMap(int width, int height, int mipCount);
|
||||
CubeMap(gpu::Texture* texture, const std::atomic<bool>& abortProcessing = false);
|
||||
CubeMap(const std::vector<QImage>& faces, gpu::Element faceFormat, int mipCount, const std::atomic<bool>& abortProcessing = false);
|
||||
|
||||
void reset(int width, int height, int mipCount);
|
||||
void copyTo(gpu::Texture* texture, const std::atomic<bool>& abortProcessing = false) const;
|
||||
|
@ -58,6 +60,7 @@ namespace image {
|
|||
private:
|
||||
|
||||
struct GGXSamples;
|
||||
struct MipMapOutputHandler;
|
||||
class Mip;
|
||||
class ConstMip;
|
||||
|
||||
|
@ -70,6 +73,7 @@ namespace image {
|
|||
|
||||
static void getFaceUV(const glm::vec3& dir, int* index, glm::vec2* uv);
|
||||
static void generateGGXSamples(GGXSamples& data, float roughness, const int resolution);
|
||||
static void copyFace(int width, int height, const glm::vec4* source, int srcLineStride, glm::vec4* dest, int dstLineStride);
|
||||
void convolveMipFaceForGGX(const GGXSamples& samples, CubeMap& output, gpu::uint16 mipLevel, int face, const std::atomic<bool>& abortProcessing) const;
|
||||
glm::vec4 computeConvolution(const glm::vec3& normal, const GGXSamples& samples) const;
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
using namespace gpu;
|
||||
|
||||
#define CPU_MIPMAPS 1
|
||||
#include <nvtt/nvtt.h>
|
||||
|
||||
#undef _CRT_SECURE_NO_WARNINGS
|
||||
#include <Etc2/Etc.h>
|
||||
|
@ -50,7 +49,7 @@ std::atomic<size_t> RECTIFIED_TEXTURE_COUNT{ 0 };
|
|||
|
||||
// we use a ref here to work around static order initialization
|
||||
// possibly causing the element not to be constructed yet
|
||||
static const auto& HDR_FORMAT = gpu::Element::COLOR_R11G11B10;
|
||||
static const auto& GPUTEXTURE_HDRFORMAT = gpu::Element::COLOR_R11G11B10;
|
||||
const QImage::Format image::QIMAGE_HDRFORMAT = QImage::Format_RGB30;
|
||||
|
||||
uint rectifyDimension(const uint& dimension) {
|
||||
|
@ -236,7 +235,7 @@ static std::function<uint32(const glm::vec3&)> getPackingFunction(const gpu::Ele
|
|||
}
|
||||
|
||||
std::function<uint32(const glm::vec3&)> getHDRPackingFunction() {
|
||||
return getPackingFunction(HDR_FORMAT);
|
||||
return getPackingFunction(GPUTEXTURE_HDRFORMAT);
|
||||
}
|
||||
|
||||
std::function<glm::vec3(gpu::uint32)> getUnpackingFunction(const gpu::Element& format) {
|
||||
|
@ -254,7 +253,7 @@ std::function<glm::vec3(gpu::uint32)> getUnpackingFunction(const gpu::Element& f
|
|||
}
|
||||
|
||||
std::function<glm::vec3(gpu::uint32)> getHDRUnpackingFunction() {
|
||||
return getUnpackingFunction(HDR_FORMAT);
|
||||
return getUnpackingFunction(GPUTEXTURE_HDRFORMAT);
|
||||
}
|
||||
|
||||
QImage processRawImageData(QIODevice& content, const std::string& filename) {
|
||||
|
@ -504,22 +503,18 @@ struct MyErrorHandler : public nvtt::ErrorHandler {
|
|||
}
|
||||
};
|
||||
|
||||
class SequentialTaskDispatcher : public nvtt::TaskDispatcher {
|
||||
public:
|
||||
SequentialTaskDispatcher(const std::atomic<bool>& abortProcessing) : _abortProcessing(abortProcessing) {};
|
||||
SequentialTaskDispatcher::SequentialTaskDispatcher(const std::atomic<bool>& abortProcessing) : _abortProcessing(abortProcessing) {
|
||||
}
|
||||
|
||||
const std::atomic<bool>& _abortProcessing;
|
||||
|
||||
virtual void dispatch(nvtt::Task* task, void* context, int count) override {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!_abortProcessing.load()) {
|
||||
task(context, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
void SequentialTaskDispatcher::dispatch(nvtt::Task* task, void* context, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!_abortProcessing.load()) {
|
||||
task(context, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void image::convertToFloat(const unsigned char* source, int width, int height, size_t srcLineByteStride, gpu::Element sourceFormat,
|
||||
glm::vec4* output, size_t outputLinePixelStride) {
|
||||
|
@ -561,6 +556,40 @@ void image::convertFromFloat(unsigned char* output, int width, int height, size_
|
|||
}
|
||||
}
|
||||
|
||||
nvtt::OutputHandler* getNVTTCompressionOutputHandler(gpu::Texture* outputTexture, int face, nvtt::CompressionOptions& compressionOptions) {
|
||||
auto outputFormat = outputTexture->getStoredMipFormat();
|
||||
|
||||
nvtt::InputFormat inputFormat = nvtt::InputFormat_RGBA_32F;
|
||||
nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror;
|
||||
nvtt::AlphaMode alphaMode = nvtt::AlphaMode_None;
|
||||
|
||||
compressionOptions.setQuality(nvtt::Quality_Production);
|
||||
|
||||
// TODO: gles: generate ETC mips instead?
|
||||
if (outputFormat == gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB) {
|
||||
compressionOptions.setFormat(nvtt::Format_BC6);
|
||||
} else if (outputFormat == gpu::Element::COLOR_RGB9E5) {
|
||||
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||
compressionOptions.setPixelFormat(32, 32, 32, 0);
|
||||
} else if (outputFormat == gpu::Element::COLOR_R11G11B10) {
|
||||
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||
compressionOptions.setPixelFormat(32, 32, 32, 0);
|
||||
} else {
|
||||
qCWarning(imagelogging) << "Unknown mip format";
|
||||
Q_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (outputFormat == gpu::Element::COLOR_RGB9E5 || outputFormat == gpu::Element::COLOR_R11G11B10) {
|
||||
// Don't use NVTT (at least version 2.1) as it outputs wrong RGB9E5 and R11G11B10F values from floats
|
||||
return new PackedFloatOutputHandler(outputTexture, face, outputFormat);
|
||||
} else {
|
||||
return new OutputHandler(outputTexture, face);
|
||||
}
|
||||
}
|
||||
|
||||
void generateHDRMips(gpu::Texture* texture, QImage&& image, BackendTarget target, const std::atomic<bool>& abortProcessing, int face) {
|
||||
// Take a local copy to force move construction
|
||||
// https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f18-for-consume-parameters-pass-by-x-and-stdmove-the-parameter
|
||||
|
@ -577,47 +606,23 @@ void generateHDRMips(gpu::Texture* texture, QImage&& image, BackendTarget target
|
|||
nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror;
|
||||
nvtt::AlphaMode alphaMode = nvtt::AlphaMode_None;
|
||||
|
||||
nvtt::CompressionOptions compressionOptions;
|
||||
compressionOptions.setQuality(nvtt::Quality_Production);
|
||||
|
||||
// TODO: gles: generate ETC mips instead?
|
||||
if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB) {
|
||||
compressionOptions.setFormat(nvtt::Format_BC6);
|
||||
} else if (mipFormat == gpu::Element::COLOR_RGB9E5) {
|
||||
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||
compressionOptions.setPixelFormat(32, 32, 32, 0);
|
||||
} else if (mipFormat == gpu::Element::COLOR_R11G11B10) {
|
||||
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||
compressionOptions.setPixelFormat(32, 32, 32, 0);
|
||||
} else {
|
||||
qCWarning(imagelogging) << "Unknown mip format";
|
||||
Q_UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
data.resize(width * height);
|
||||
convertToFloat(localCopy.bits(), width, height, localCopy.bytesPerLine(), HDR_FORMAT, data.data(), width);
|
||||
convertToFloat(localCopy.bits(), width, height, localCopy.bytesPerLine(), GPUTEXTURE_HDRFORMAT, data.data(), width);
|
||||
|
||||
// We're done with the localCopy, free up the memory to avoid bloating the heap
|
||||
localCopy = QImage(); // QImage doesn't have a clear function, so override it with an empty one.
|
||||
|
||||
nvtt::OutputOptions outputOptions;
|
||||
outputOptions.setOutputHeader(false);
|
||||
std::unique_ptr<nvtt::OutputHandler> outputHandler;
|
||||
|
||||
nvtt::CompressionOptions compressionOptions;
|
||||
std::unique_ptr<nvtt::OutputHandler> outputHandler{ getNVTTCompressionOutputHandler(texture, face, compressionOptions) };
|
||||
|
||||
MyErrorHandler errorHandler;
|
||||
outputOptions.setErrorHandler(&errorHandler);
|
||||
nvtt::Context context;
|
||||
int mipLevel = 0;
|
||||
|
||||
if (mipFormat == gpu::Element::COLOR_RGB9E5 || mipFormat == gpu::Element::COLOR_R11G11B10) {
|
||||
// Don't use NVTT (at least version 2.1) as it outputs wrong RGB9E5 and R11G11B10F values from floats
|
||||
outputHandler.reset(new PackedFloatOutputHandler(texture, face, mipFormat));
|
||||
} else {
|
||||
outputHandler.reset(new OutputHandler(texture, face));
|
||||
}
|
||||
|
||||
outputOptions.setOutputHandler(outputHandler.get());
|
||||
|
||||
nvtt::Surface surface;
|
||||
|
@ -836,27 +841,27 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, BackendTarget target
|
|||
|
||||
#endif
|
||||
|
||||
void generateMips(gpu::Texture* texture, QImage&& image, BackendTarget target, const std::atomic<bool>& abortProcessing = false, int face = -1, bool forceCPUBuild = false) {
|
||||
if (forceCPUBuild || CPU_MIPMAPS) {
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
void generateMips(gpu::Texture* texture, QImage&& image, BackendTarget target, const std::atomic<bool>& abortProcessing = false, int face = -1) {
|
||||
#if CPU_MIPMAPS
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
|
||||
if (target == BackendTarget::GLES32) {
|
||||
generateLDRMips(texture, std::move(image), target, abortProcessing, face);
|
||||
} else {
|
||||
if (image.format() == QIMAGE_HDRFORMAT) {
|
||||
generateHDRMips(texture, std::move(image), target, abortProcessing, face);
|
||||
} else {
|
||||
generateLDRMips(texture, std::move(image), target, abortProcessing, face);
|
||||
}
|
||||
}
|
||||
if (target == BackendTarget::GLES32) {
|
||||
generateLDRMips(texture, std::move(image), target, abortProcessing, face);
|
||||
} else {
|
||||
texture->setAutoGenerateMips(true);
|
||||
if (image.format() == QIMAGE_HDRFORMAT) {
|
||||
generateHDRMips(texture, std::move(image), target, abortProcessing, face);
|
||||
} else {
|
||||
generateLDRMips(texture, std::move(image), target, abortProcessing, face);
|
||||
}
|
||||
}
|
||||
#else
|
||||
texture->setAutoGenerateMips(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void convolveForGGX(gpu::Texture* texture, BackendTarget target, const std::atomic<bool>& abortProcessing = false) {
|
||||
void convolveForGGX(const std::vector<QImage>& faces, gpu::Element faceFormat, gpu::Texture* texture, const std::atomic<bool>& abortProcessing = false) {
|
||||
PROFILE_RANGE(resource_parse, "convolveForGGX");
|
||||
CubeMap source(texture, abortProcessing);
|
||||
CubeMap source(faces, faceFormat, texture->getNumMips(), abortProcessing);
|
||||
CubeMap output(texture->getWidth(), texture->getHeight(), texture->getNumMips());
|
||||
|
||||
source.convolveForGGX(output, abortProcessing);
|
||||
|
@ -1488,7 +1493,7 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
|
|||
if (targetCubemapFormat == QIMAGE_HDRFORMAT && image.format() != targetCubemapFormat) {
|
||||
// If the target format is HDR but the image isn't, we need to convert the
|
||||
// image to HDR.
|
||||
image = convertToHDRFormat(std::move(image), HDR_FORMAT);
|
||||
image = convertToHDRFormat(std::move(image), GPUTEXTURE_HDRFORMAT);
|
||||
} else if (image.format() == QIMAGE_HDRFORMAT && image.format() != targetCubemapFormat) {
|
||||
// If the target format isn't HDR (such as on GLES) but the image is, we need to
|
||||
// convert the image to LDR
|
||||
|
@ -1504,7 +1509,7 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
|
|||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB;
|
||||
}
|
||||
} else {
|
||||
formatGPU = HDR_FORMAT;
|
||||
formatGPU = GPUTEXTURE_HDRFORMAT;
|
||||
}
|
||||
|
||||
formatMip = formatGPU;
|
||||
|
@ -1559,7 +1564,7 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
|
|||
if (target == BackendTarget::GLES32) {
|
||||
irradianceFormat = gpu::Element::COLOR_SRGBA_32;
|
||||
} else {
|
||||
irradianceFormat = HDR_FORMAT;
|
||||
irradianceFormat = GPUTEXTURE_HDRFORMAT;
|
||||
}
|
||||
|
||||
auto irradianceTexture = gpu::Texture::createCube(irradianceFormat, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
|
@ -1575,14 +1580,16 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
|
|||
theTexture->overrideIrradiance(irradiance);
|
||||
}
|
||||
|
||||
for (uint8 face = 0; face < faces.size(); ++face) {
|
||||
// Force building the mip maps right now on CPU if we are convolving for GGX later on
|
||||
generateMips(theTexture.get(), std::move(faces[face]), target, abortProcessing, face, (options & CUBE_GGX_CONVOLVE) == CUBE_GGX_CONVOLVE);
|
||||
if (options & CUBE_GGX_CONVOLVE) {
|
||||
convolveForGGX(faces, GPUTEXTURE_HDRFORMAT, theTexture.get(), abortProcessing);
|
||||
} else {
|
||||
// Create mip maps and compress to final format in one go
|
||||
for (uint8 face = 0; face < faces.size(); ++face) {
|
||||
// Force building the mip maps right now on CPU if we are convolving for GGX later on
|
||||
generateMips(theTexture.get(), std::move(faces[face]), target, abortProcessing, face);
|
||||
}
|
||||
}
|
||||
|
||||
if (options & CUBE_GGX_CONVOLVE) {
|
||||
convolveForGGX(theTexture.get(), target, abortProcessing);
|
||||
}
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QVariant>
|
||||
#include <QImage>
|
||||
#include <nvtt/nvtt.h>
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
|
||||
|
@ -107,6 +108,18 @@ gpu::TexturePointer processImage(std::shared_ptr<QIODevice> content, const std::
|
|||
int maxNumPixels, TextureUsage::Type textureType,
|
||||
bool compress, gpu::BackendTarget target, const std::atomic<bool>& abortProcessing = false);
|
||||
|
||||
#if defined(NVTT_API)
|
||||
class SequentialTaskDispatcher : public nvtt::TaskDispatcher {
|
||||
public:
|
||||
SequentialTaskDispatcher(const std::atomic<bool>& abortProcessing);
|
||||
|
||||
const std::atomic<bool>& _abortProcessing;
|
||||
|
||||
void dispatch(nvtt::Task* task, void* context, int count) override;
|
||||
};
|
||||
|
||||
nvtt::OutputHandler* getNVTTCompressionOutputHandler(gpu::Texture* outputTexture, int face, nvtt::CompressionOptions& compressOptions);
|
||||
#endif
|
||||
} // namespace image
|
||||
|
||||
#endif // hifi_image_Image_h
|
||||
|
|
Loading…
Reference in a new issue