mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 19:55:07 +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:
|
||||
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -120,32 +120,36 @@ void GL45Texture::generateMips() const {
|
|||
(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;
|
||||
if (!texture.isStoredMipFaceAvailable(sourceMip)) {
|
||||
return;
|
||||
}
|
||||
size_t maxFace = GLTexture::getFaceCount(_target);
|
||||
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||
auto size = texture.evalMipDimensions(sourceMip);
|
||||
auto mipData = texture.accessStoredMipFace(sourceMip, face);
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), mipData->getFormat());
|
||||
if (GL_TEXTURE_2D == _target) {
|
||||
glTextureSubImage2D(_id, targetMip, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mipData->readData());
|
||||
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
||||
// DSA ARB does not work on AMD, so use EXT
|
||||
// unless EXT is not available on the driver
|
||||
if (glTextureSubImage2DEXT) {
|
||||
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
|
||||
glTextureSubImage2DEXT(_id, target, targetMip, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mipData->readData());
|
||||
} else {
|
||||
glTextureSubImage3D(_id, targetMip, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mipData->readData());
|
||||
}
|
||||
auto mipDimensions = texture.evalMipDimensions(sourceMip);
|
||||
glm::uvec3 size = { mipDimensions.x, lines, mipDimensions.z };
|
||||
auto mipData = texture.accessStoredMipFace(sourceMip, face);
|
||||
auto sourcePointer = mipData->readData() + dataOffset;
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), mipData->getFormat());
|
||||
if (GL_TEXTURE_2D == _target) {
|
||||
glTextureSubImage2D(_id, targetMip, 0, lineOffset, size.x, size.y, texelFormat.format, texelFormat.type, sourcePointer);
|
||||
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
||||
// DSA ARB does not work on AMD, so use EXT
|
||||
// unless EXT is not available on the driver
|
||||
if (glTextureSubImage2DEXT) {
|
||||
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
|
||||
glTextureSubImage2DEXT(_id, target, targetMip, 0, lineOffset, size.x, size.y, texelFormat.format, texelFormat.type, sourcePointer);
|
||||
} 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 {
|
||||
|
@ -221,7 +225,10 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr<GLBacke
|
|||
auto mipLevels = _gpuObject.evalNumMips();
|
||||
for (uint16_t sourceMip = 0; sourceMip < mipLevels; ++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()) {
|
||||
generateMips();
|
||||
|
|
|
@ -359,9 +359,12 @@ void GL45ResourceTexture::allocateStorage(uint16 allocatedMip) {
|
|||
|
||||
void GL45ResourceTexture::copyMipsFromTexture() {
|
||||
auto mipLevels = _gpuObject.evalNumMips();
|
||||
size_t maxFace = GLTexture::getFaceCount(_target);
|
||||
for (uint16_t sourceMip = _populatedMip; sourceMip < mipLevels; ++sourceMip) {
|
||||
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;
|
||||
}
|
||||
|
||||
for (int16_t mip = _populatedMip - 1; mip >= _allocatedMip; --mip) {
|
||||
// FIXME break down the transfers into chunks so that no single transfer is
|
||||
// consuming more than X bandwidth
|
||||
_pendingTransfers.push([mip, this] {
|
||||
Q_ASSERT(mip >= _allocatedMip);
|
||||
// FIXME modify the copy mechanism to be incremental
|
||||
copyMipFromTexture(mip, mip - _allocatedMip);
|
||||
_populatedMip = mip;
|
||||
static const uvec3 MAX_TRANSFER_DIMENSIONS { 512, 512, 1 };
|
||||
static const size_t MAX_TRANSFER_SIZE = MAX_TRANSFER_DIMENSIONS.x * MAX_TRANSFER_DIMENSIONS.y * 4;
|
||||
const uint8_t maxFace = GLTexture::getFaceCount(_target);
|
||||
|
||||
uint16_t sourceMip = _populatedMip;
|
||||
do {
|
||||
--sourceMip;
|
||||
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();
|
||||
});
|
||||
}
|
||||
} while (sourceMip != _allocatedMip);
|
||||
}
|
||||
|
||||
// Sparsely allocated, managed size resource textures
|
||||
|
|
Loading…
Reference in a new issue