mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 06:38:40 +02:00
Add incremental transfers for large mips
This commit is contained in:
parent
7fb7aa87eb
commit
1238edd0d7
3 changed files with 82 additions and 31 deletions
|
@ -38,7 +38,8 @@ public:
|
||||||
protected:
|
protected:
|
||||||
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
|
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
|
||||||
void generateMips() const override;
|
void generateMips() const override;
|
||||||
void copyMipFromTexture(uint16_t sourceMip, uint16_t targetMip) const;
|
void copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const;
|
||||||
|
void copyMipFaceLinesFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lineOffset, uint32_t lines, size_t dataOffset) const;
|
||||||
virtual void syncSampler() const;
|
virtual void syncSampler() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -120,32 +120,36 @@ void GL45Texture::generateMips() const {
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL45Texture::copyMipFromTexture(uint16_t sourceMip, uint16_t targetMip) const {
|
void GL45Texture::copyMipFaceLinesFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lineOffset, uint32_t lines, size_t dataOffset) const {
|
||||||
const auto& texture = _gpuObject;
|
const auto& texture = _gpuObject;
|
||||||
if (!texture.isStoredMipFaceAvailable(sourceMip)) {
|
if (!texture.isStoredMipFaceAvailable(sourceMip)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
size_t maxFace = GLTexture::getFaceCount(_target);
|
auto mipDimensions = texture.evalMipDimensions(sourceMip);
|
||||||
for (uint8_t face = 0; face < maxFace; ++face) {
|
glm::uvec3 size = { mipDimensions.x, lines, mipDimensions.z };
|
||||||
auto size = texture.evalMipDimensions(sourceMip);
|
auto mipData = texture.accessStoredMipFace(sourceMip, face);
|
||||||
auto mipData = texture.accessStoredMipFace(sourceMip, face);
|
auto sourcePointer = mipData->readData() + dataOffset;
|
||||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), mipData->getFormat());
|
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), mipData->getFormat());
|
||||||
if (GL_TEXTURE_2D == _target) {
|
if (GL_TEXTURE_2D == _target) {
|
||||||
glTextureSubImage2D(_id, targetMip, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mipData->readData());
|
glTextureSubImage2D(_id, targetMip, 0, lineOffset, size.x, size.y, texelFormat.format, texelFormat.type, sourcePointer);
|
||||||
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
||||||
// DSA ARB does not work on AMD, so use EXT
|
// DSA ARB does not work on AMD, so use EXT
|
||||||
// unless EXT is not available on the driver
|
// unless EXT is not available on the driver
|
||||||
if (glTextureSubImage2DEXT) {
|
if (glTextureSubImage2DEXT) {
|
||||||
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
|
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
|
||||||
glTextureSubImage2DEXT(_id, target, targetMip, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mipData->readData());
|
glTextureSubImage2DEXT(_id, target, targetMip, 0, lineOffset, size.x, size.y, texelFormat.format, texelFormat.type, sourcePointer);
|
||||||
} else {
|
|
||||||
glTextureSubImage3D(_id, targetMip, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mipData->readData());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(false);
|
glTextureSubImage3D(_id, targetMip, 0, lineOffset, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, sourcePointer);
|
||||||
}
|
}
|
||||||
(void)CHECK_GL_ERROR();
|
} else {
|
||||||
|
Q_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL45Texture::copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const {
|
||||||
|
auto size = _gpuObject.evalMipDimensions(sourceMip);
|
||||||
|
copyMipFaceLinesFromTexture(sourceMip, targetMip, face, 0, size.y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL45Texture::syncSampler() const {
|
void GL45Texture::syncSampler() const {
|
||||||
|
@ -221,7 +225,10 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr<GLBacke
|
||||||
auto mipLevels = _gpuObject.evalNumMips();
|
auto mipLevels = _gpuObject.evalNumMips();
|
||||||
for (uint16_t sourceMip = 0; sourceMip < mipLevels; ++sourceMip) {
|
for (uint16_t sourceMip = 0; sourceMip < mipLevels; ++sourceMip) {
|
||||||
uint16_t targetMip = sourceMip;
|
uint16_t targetMip = sourceMip;
|
||||||
copyMipFromTexture(sourceMip, targetMip);
|
size_t maxFace = GLTexture::getFaceCount(_target);
|
||||||
|
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||||
|
copyMipFaceFromTexture(sourceMip, targetMip, face);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (texture.isAutogenerateMips()) {
|
if (texture.isAutogenerateMips()) {
|
||||||
generateMips();
|
generateMips();
|
||||||
|
|
|
@ -359,9 +359,12 @@ void GL45ResourceTexture::allocateStorage(uint16 allocatedMip) {
|
||||||
|
|
||||||
void GL45ResourceTexture::copyMipsFromTexture() {
|
void GL45ResourceTexture::copyMipsFromTexture() {
|
||||||
auto mipLevels = _gpuObject.evalNumMips();
|
auto mipLevels = _gpuObject.evalNumMips();
|
||||||
|
size_t maxFace = GLTexture::getFaceCount(_target);
|
||||||
for (uint16_t sourceMip = _populatedMip; sourceMip < mipLevels; ++sourceMip) {
|
for (uint16_t sourceMip = _populatedMip; sourceMip < mipLevels; ++sourceMip) {
|
||||||
uint16_t targetMip = sourceMip - _allocatedMip;
|
uint16_t targetMip = sourceMip - _allocatedMip;
|
||||||
copyMipFromTexture(sourceMip, targetMip);
|
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||||
|
copyMipFaceFromTexture(sourceMip, targetMip, face);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,17 +451,57 @@ void GL45ResourceTexture::populateTransferQueue() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int16_t mip = _populatedMip - 1; mip >= _allocatedMip; --mip) {
|
static const uvec3 MAX_TRANSFER_DIMENSIONS { 512, 512, 1 };
|
||||||
// FIXME break down the transfers into chunks so that no single transfer is
|
static const size_t MAX_TRANSFER_SIZE = MAX_TRANSFER_DIMENSIONS.x * MAX_TRANSFER_DIMENSIONS.y * 4;
|
||||||
// consuming more than X bandwidth
|
const uint8_t maxFace = GLTexture::getFaceCount(_target);
|
||||||
_pendingTransfers.push([mip, this] {
|
|
||||||
Q_ASSERT(mip >= _allocatedMip);
|
uint16_t sourceMip = _populatedMip;
|
||||||
// FIXME modify the copy mechanism to be incremental
|
do {
|
||||||
copyMipFromTexture(mip, mip - _allocatedMip);
|
--sourceMip;
|
||||||
_populatedMip = mip;
|
auto targetMip = sourceMip - _allocatedMip;
|
||||||
|
auto mipDimensions = _gpuObject.evalMipDimensions(sourceMip);
|
||||||
|
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||||
|
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, face)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the mip is less than the max transfer size, then just do it in one transfer
|
||||||
|
if (glm::all(glm::lessThanEqual(mipDimensions, MAX_TRANSFER_DIMENSIONS))) {
|
||||||
|
// Can the mip be transferred in one go
|
||||||
|
_pendingTransfers.push([=] {
|
||||||
|
Q_ASSERT(sourceMip >= _allocatedMip);
|
||||||
|
// FIXME modify the copy mechanism to be incremental
|
||||||
|
copyMipFaceFromTexture(sourceMip, targetMip, face);
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// break down the transfers into chunks so that no single transfer is
|
||||||
|
// consuming more than X bandwidth
|
||||||
|
auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face);
|
||||||
|
const auto lines = mipDimensions.y;
|
||||||
|
auto bytesPerLine = (uint32_t)mipData->getSize() / lines;
|
||||||
|
Q_ASSERT(0 == (mipData->getSize() % lines));
|
||||||
|
auto linesPerTransfer = MAX_TRANSFER_SIZE / bytesPerLine;
|
||||||
|
size_t offset = 0;
|
||||||
|
uint32_t lineOffset = 0;
|
||||||
|
while (lineOffset < lines) {
|
||||||
|
uint32_t linesToCopy = std::min<uint32_t>(lines - lineOffset, linesPerTransfer);
|
||||||
|
uvec3 size { mipDimensions.x, linesToCopy, 1 };
|
||||||
|
_pendingTransfers.push([=] {
|
||||||
|
copyMipFaceLinesFromTexture(sourceMip, targetMip, face, lineOffset, linesToCopy, offset);
|
||||||
|
});
|
||||||
|
lineOffset += linesToCopy;
|
||||||
|
offset += (linesToCopy * bytesPerLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// queue up the sampler and populated mip change for after the transfer has completed
|
||||||
|
_pendingTransfers.push([=] {
|
||||||
|
_populatedMip = targetMip;
|
||||||
syncSampler();
|
syncSampler();
|
||||||
});
|
});
|
||||||
}
|
} while (sourceMip != _allocatedMip);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sparsely allocated, managed size resource textures
|
// Sparsely allocated, managed size resource textures
|
||||||
|
|
Loading…
Reference in a new issue