GLES: Use mapped device memory when possible.

This commit is contained in:
Unknown W. Brackets 2018-02-11 11:17:34 -08:00
parent adbd8d005c
commit 9eb51a6a36
3 changed files with 99 additions and 22 deletions

View File

@ -770,6 +770,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
// TODO: Add fast path for glBindVertexBuffer
GLRInputLayout *layout = c.bindVertexBuffer.inputLayout;
GLuint buf = c.bindVertexBuffer.buffer ? c.bindVertexBuffer.buffer->buffer : 0;
assert(!c.bindVertexBuffer.buffer->Mapped());
if (buf != curArrayBuffer) {
glBindBuffer(GL_ARRAY_BUFFER, buf);
curArrayBuffer = buf;
@ -797,12 +798,14 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
Crash();
} else if (c.bind_buffer.target == GL_ELEMENT_ARRAY_BUFFER) {
GLuint buf = c.bind_buffer.buffer ? c.bind_buffer.buffer->buffer : 0;
assert(!c.bind_buffer.buffer->Mapped());
if (buf != curElemArrayBuffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
curElemArrayBuffer = buf;
}
} else {
GLuint buf = c.bind_buffer.buffer ? c.bind_buffer.buffer->buffer : 0;
assert(!c.bind_buffer.buffer->Mapped());
glBindBuffer(c.bind_buffer.target, buf);
}
break;

View File

@ -421,6 +421,11 @@ void GLRenderManager::Run(int frame) {
BeginSubmitFrame(frame);
FrameData &frameData = frameData_[frame];
for (auto iter : frameData.activePushBuffers) {
iter->Flush();
iter->UnmapDevice();
}
auto &stepsOnThread = frameData_[frame].steps;
auto &initStepsOnThread = frameData_[frame].initSteps;
// queueRunner_.LogSteps(stepsOnThread);
@ -429,6 +434,10 @@ void GLRenderManager::Run(int frame) {
stepsOnThread.clear();
initStepsOnThread.clear();
for (auto iter : frameData.activePushBuffers) {
iter->MapDevice();
}
switch (frameData.type) {
case GLRRunType::END:
EndSubmitFrame(frame);
@ -446,11 +455,6 @@ void GLRenderManager::Run(int frame) {
}
void GLRenderManager::FlushSync() {
// Need to flush any pushbuffers to VRAM before submitting draw calls.
for (auto iter : frameData_[curFrame_].activePushBuffers) {
iter->Flush();
}
// TODO: Reset curRenderStep_?
int curFrame = curFrame_;
FrameData &frameData = frameData_[curFrame];
@ -532,42 +536,51 @@ GLPushBuffer::~GLPushBuffer() {
void GLPushBuffer::Map() {
assert(!writePtr_);
// TODO: Even a good old glMapBuffer could actually work well here.
writePtr_ = buffers_[buf_].deviceMemory;
auto &info = buffers_[buf_];
writePtr_ = info.deviceMemory ? info.deviceMemory : info.localMemory;
// Force alignment. This is needed for PushAligned() to work as expected.
while ((intptr_t)writePtr_ & 15) {
writePtr_++;
}
assert(writePtr_);
}
void GLPushBuffer::Unmap() {
assert(writePtr_);
// Here we simply upload the data to the last buffer.
// Might be worth trying with size_ instead of offset_, so the driver can replace
// the whole buffer. At least if it's close.
render_->BufferSubdata(buffers_[buf_].buffer, 0, offset_, buffers_[buf_].deviceMemory, false);
if (!buffers_[buf_].deviceMemory) {
// Here we simply upload the data to the last buffer.
// Might be worth trying with size_ instead of offset_, so the driver can replace
// the whole buffer. At least if it's close.
render_->BufferSubdata(buffers_[buf_].buffer, 0, offset_, buffers_[buf_].localMemory, false);
}
writePtr_ = nullptr;
}
void GLPushBuffer::Flush() {
render_->BufferSubdata(buffers_[buf_].buffer, 0, offset_, buffers_[buf_].deviceMemory, false);
// Here we will submit all the draw calls, with the already known buffer and offsets.
// Might as well reset the write pointer here and start over the current buffer.
writePtr_ = buffers_[buf_].deviceMemory;
offset_ = 0;
// We don't need to do this for device memory.
if (!buffers_[buf_].deviceMemory && writePtr_) {
render_->BufferSubdata(buffers_[buf_].buffer, 0, offset_, buffers_[buf_].localMemory, false);
// Here we will submit all the draw calls, with the already known buffer and offsets.
// Might as well reset the write pointer here and start over the current buffer.
writePtr_ = buffers_[buf_].localMemory;
offset_ = 0;
}
}
bool GLPushBuffer::AddBuffer() {
BufInfo info;
info.deviceMemory = new uint8_t[size_];
info.localMemory = new uint8_t[size_];
info.buffer = render_->CreateBuffer(target_, size_, GL_DYNAMIC_DRAW);
buf_ = buffers_.size();
buffers_.resize(buf_ + 1);
buffers_[buf_] = info;
buffers_.push_back(info);
return true;
}
void GLPushBuffer::Destroy() {
for (BufInfo &info : buffers_) {
// This will automatically unmap device memory, if needed.
render_->DeleteBuffer(info.buffer);
delete[] info.deviceMemory;
delete[] info.localMemory;
}
buffers_.clear();
}
@ -617,3 +630,37 @@ size_t GLPushBuffer::GetTotalSize() const {
sum += offset_;
return sum;
}
void GLPushBuffer::MapDevice() {
for (auto &info : buffers_) {
assert(!info.deviceMemory);
// TODO: Can we use GL_WRITE_ONLY?
info.deviceMemory = (uint8_t *)info.buffer->Map(GL_READ_WRITE);
if (info.deviceMemory) {
delete[] info.localMemory;
info.localMemory = nullptr;
} else if (!info.localMemory) {
// Somehow it failed, let's dodge crashing.
info.localMemory = new uint8_t[info.buffer->size_];
}
assert(info.localMemory || info.deviceMemory);
}
if (writePtr_) {
// This can happen during a sync. Remap.
writePtr_ = nullptr;
Map();
}
}
void GLPushBuffer::UnmapDevice() {
for (auto &info : buffers_) {
if (info.deviceMemory) {
// TODO: Technically this can return false?
info.buffer->Unmap();
info.deviceMemory = nullptr;
}
}
}

View File

@ -138,10 +138,30 @@ public:
glDeleteBuffers(1, &buffer);
}
}
void *Map(GLenum access) {
glBindBuffer(target_, buffer);
void *p = glMapBuffer(target_, access);
mapped_ = p != nullptr;
return p;
}
bool Unmap() {
glBindBuffer(target_, buffer);
mapped_ = false;
return glUnmapBuffer(target_) == GL_TRUE;
}
bool Mapped() {
return mapped_;
}
GLuint buffer = 0;
GLuint target_;
int size_;
private:
bool mapped_ = false;
};
enum class GLRRunType {
@ -747,8 +767,9 @@ private:
class GLPushBuffer {
public:
struct BufInfo {
GLRBuffer *buffer;
uint8_t *deviceMemory;
GLRBuffer *buffer = nullptr;
uint8_t *localMemory = nullptr;
uint8_t *deviceMemory = nullptr;
};
public:
@ -835,6 +856,10 @@ public:
void Flush();
protected:
void MapDevice();
void UnmapDevice();
private:
bool AddBuffer();
void NextBuffer(size_t minSize);
@ -847,4 +872,6 @@ private:
size_t size_ = 0;
uint8_t *writePtr_ = nullptr;
GLuint target_;
friend class GLRenderManager;
};