Fix transfer buffering

This commit is contained in:
Brad Davis 2017-02-17 13:00:38 -08:00
parent 285222d490
commit eafe0a04d5
2 changed files with 34 additions and 30 deletions

View file

@ -108,16 +108,10 @@ public:
using VoidLambdaQueue = std::queue<VoidLambda>; using VoidLambdaQueue = std::queue<VoidLambda>;
using ThreadPointer = std::shared_ptr<std::thread>; using ThreadPointer = std::shared_ptr<std::thread>;
const GL45VariableAllocationTexture& _parent; const GL45VariableAllocationTexture& _parent;
const uint16_t _sourceMip;
const uint16_t _targetMip;
const uint8_t _face;
const uint32_t _lines;
const uint32_t _lineOffset;
// Holds the contents to transfer to the GPU in CPU memory // Holds the contents to transfer to the GPU in CPU memory
std::vector<uint8_t> _buffer; std::vector<uint8_t> _buffer;
// Indicates if a transfer from backing storage to interal storage has started // Indicates if a transfer from backing storage to interal storage has started
bool _bufferingStarted { false }; bool _bufferingStarted { false };
bool _transferOnly { false };
bool _bufferingCompleted { false }; bool _bufferingCompleted { false };
VoidLambda _transferLambda; VoidLambda _transferLambda;
VoidLambda _bufferingLambda; VoidLambda _bufferingLambda;
@ -128,6 +122,7 @@ public:
static void bufferLoop(); static void bufferLoop();
public: public:
TransferJob(const TransferJob& other) = delete;
TransferJob(const GL45VariableAllocationTexture& parent, std::function<void()> transferLambda); TransferJob(const GL45VariableAllocationTexture& parent, std::function<void()> transferLambda);
TransferJob(const GL45VariableAllocationTexture& parent, uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lines = 0, uint32_t lineOffset = 0); TransferJob(const GL45VariableAllocationTexture& parent, uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lines = 0, uint32_t lineOffset = 0);
bool tryTransfer(); bool tryTransfer();
@ -139,7 +134,7 @@ public:
void transfer(); void transfer();
}; };
using TransferQueue = std::queue<TransferJob>; using TransferQueue = std::queue<std::unique_ptr<TransferJob>>;
static MemoryPressureState _memoryPressureState; static MemoryPressureState _memoryPressureState;
protected: protected:
static std::atomic<bool> _memoryPressureStateStale; static std::atomic<bool> _memoryPressureStateStale;

View file

@ -78,11 +78,18 @@ void TransferJob::stopTransferLoop() {
} }
TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lines, uint32_t lineOffset) TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lines, uint32_t lineOffset)
: _parent(parent), _sourceMip(sourceMip), _targetMip(targetMip), _face(face), _lines(lines), _lineOffset(lineOffset) { : _parent(parent) {
auto transferDimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
GLenum format;
GLenum type;
auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), mipData->getFormat());
format = texelFormat.format;
type = texelFormat.type;
if (0 == lines) { if (0 == lines) {
_bufferingLambda = [this] { _bufferingLambda = [=] {
auto mipData = _parent._gpuObject.accessStoredMipFace(_sourceMip, _face);
auto size = mipData->getSize(); auto size = mipData->getSize();
_buffer.resize(size); _buffer.resize(size);
memcpy(&_buffer[0], mipData->readData(), size); memcpy(&_buffer[0], mipData->readData(), size);
@ -90,38 +97,39 @@ TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t s
}; };
} else { } else {
_bufferingLambda = [this] { transferDimensions.y = lines;
auto mipData = _parent._gpuObject.accessStoredMipFace(_sourceMip, _face); _bufferingLambda = [=] {
auto dimensions = _parent._gpuObject.evalMipDimensions(_sourceMip); auto dimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
auto mipSize = mipData->getSize(); auto mipSize = mipData->getSize();
auto bytesPerLine = (uint32_t)mipSize / dimensions.y; auto bytesPerLine = (uint32_t)mipSize / dimensions.y;
auto transferSize = bytesPerLine * _lines; auto transferSize = bytesPerLine * lines;
auto sourceOffset = bytesPerLine * _lineOffset; auto sourceOffset = bytesPerLine * lineOffset;
_buffer.resize(transferSize); _buffer.resize(transferSize);
memcpy(&_buffer[0], mipData->readData() + sourceOffset, transferSize); memcpy(&_buffer[0], mipData->readData() + sourceOffset, transferSize);
_bufferingCompleted = true; _bufferingCompleted = true;
}; };
} }
_transferLambda = [this] { _transferLambda = [=] {
auto mipData = _parent._gpuObject.accessStoredMipFace(_sourceMip, _face); _parent.copyMipFaceLinesFromTexture(targetMip, face, transferDimensions, lineOffset, format, type, _buffer.data());
auto dimensions = _parent._gpuObject.evalMipDimensions(_sourceMip);
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), mipData->getFormat());
_parent.copyMipFaceLinesFromTexture(_targetMip, _face, dimensions, _lineOffset, texelFormat.format, texelFormat.type, &_buffer[0]);
_buffer.swap(std::vector<uint8_t>()); _buffer.swap(std::vector<uint8_t>());
}; };
} }
TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, std::function<void()> transferLambda) TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, std::function<void()> transferLambda)
: _parent(parent), _sourceMip(0), _targetMip(0), _face(0), _lines(0), _lineOffset(0), _bufferingCompleted(true), _transferLambda(transferLambda) { : _parent(parent), _bufferingCompleted(true), _transferLambda(transferLambda) {
if (!_bufferThread) {
_bufferThread = std::make_shared<std::thread>([] {
TransferJob::bufferLoop();
});
}
} }
bool TransferJob::tryTransfer() { bool TransferJob::tryTransfer() {
// Disable threaded texture transfer for now
#if 1
if (!_bufferingCompleted) {
_bufferingLambda();
_bufferingCompleted = true;
}
_transferLambda();
return true;
#else
// Are we ready to transfer // Are we ready to transfer
if (_bufferingCompleted) { if (_bufferingCompleted) {
_transferLambda(); _transferLambda();
@ -130,6 +138,7 @@ bool TransferJob::tryTransfer() {
startBuffering(); startBuffering();
return false; return false;
#endif
} }
void TransferJob::startBuffering() { void TransferJob::startBuffering() {
@ -391,7 +400,7 @@ void GL45VariableAllocationTexture::executeNextTransfer(const TexturePointer& cu
if (!_pendingTransfers.empty()) { if (!_pendingTransfers.empty()) {
// Keeping hold of a strong pointer during the transfer ensures that the transfer thread cannot try to access a destroyed texture // Keeping hold of a strong pointer during the transfer ensures that the transfer thread cannot try to access a destroyed texture
_currentTransferTexture = currentTexture; _currentTransferTexture = currentTexture;
if (_pendingTransfers.front().tryTransfer()) { if (_pendingTransfers.front()->tryTransfer()) {
_pendingTransfers.pop(); _pendingTransfers.pop();
_currentTransferTexture.reset(); _currentTransferTexture.reset();
} }
@ -542,7 +551,7 @@ void GL45ResourceTexture::populateTransferQueue() {
// If the mip is less than the max transfer size, then just do it in one transfer // 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))) { if (glm::all(glm::lessThanEqual(mipDimensions, MAX_TRANSFER_DIMENSIONS))) {
// Can the mip be transferred in one go // Can the mip be transferred in one go
_pendingTransfers.emplace(*this, sourceMip, targetMip, face); _pendingTransfers.emplace(new TransferJob(*this, sourceMip, targetMip, face));
continue; continue;
} }
@ -556,13 +565,13 @@ void GL45ResourceTexture::populateTransferQueue() {
uint32_t lineOffset = 0; uint32_t lineOffset = 0;
while (lineOffset < lines) { while (lineOffset < lines) {
uint32_t linesToCopy = std::min<uint32_t>(lines - lineOffset, linesPerTransfer); uint32_t linesToCopy = std::min<uint32_t>(lines - lineOffset, linesPerTransfer);
_pendingTransfers.emplace(TransferJob(*this, sourceMip, targetMip, face, linesToCopy, lineOffset)); _pendingTransfers.emplace(new TransferJob(*this, sourceMip, targetMip, face, linesToCopy, lineOffset));
lineOffset += linesToCopy; lineOffset += linesToCopy;
} }
} }
// queue up the sampler and populated mip change for after the transfer has completed // queue up the sampler and populated mip change for after the transfer has completed
_pendingTransfers.emplace(TransferJob(*this, [=] { _pendingTransfers.emplace(new TransferJob(*this, [=] {
_populatedMip = sourceMip; _populatedMip = sourceMip;
syncSampler(); syncSampler();
})); }));