Merge pull request #10875 from hrydgard/more-gl-shutdown-fixes

More GL shutdown fixes
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2018-04-05 20:19:11 +02:00
commit 4624d09e29
8 files changed
+234 -171

No files matched your search

+8 -14
View File
@@ -109,11 +109,9 @@ void DrawEngineGLES::DeviceRestore() {
void DrawEngineGLES::InitDeviceObjects() {
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
frameData_[i].pushVertex = new GLPushBuffer(render_, GL_ARRAY_BUFFER, 1024 * 1024);
frameData_[i].pushIndex = new GLPushBuffer(render_, GL_ELEMENT_ARRAY_BUFFER, 256 * 1024);
frameData_[i].pushVertex = render_->CreatePushBuffer(i, GL_ARRAY_BUFFER, 1024 * 1024);
frameData_[i].pushIndex = render_->CreatePushBuffer(i, GL_ELEMENT_ARRAY_BUFFER, 256 * 1024);
render_->RegisterPushBuffer(i, frameData_[i].pushVertex);
render_->RegisterPushBuffer(i, frameData_[i].pushIndex);
}
int vertexSize = sizeof(TransformedVertex);
@@ -131,12 +129,8 @@ void DrawEngineGLES::DestroyDeviceObjects() {
if (!frameData_[i].pushVertex && !frameData_[i].pushIndex)
continue;
render_->UnregisterPushBuffer(i, frameData_[i].pushVertex);
render_->UnregisterPushBuffer(i, frameData_[i].pushIndex);
frameData_[i].pushVertex->Destroy();
frameData_[i].pushIndex->Destroy();
delete frameData_[i].pushVertex;
delete frameData_[i].pushIndex;
render_->DeletePushBuffer(frameData_[i].pushVertex);
render_->DeletePushBuffer(frameData_[i].pushIndex);
frameData_[i].pushVertex = nullptr;
frameData_[i].pushIndex = nullptr;
}
@@ -159,14 +153,14 @@ void DrawEngineGLES::ClearInputLayoutMap() {
void DrawEngineGLES::BeginFrame() {
FrameData &frameData = frameData_[render_->GetCurFrame()];
frameData.pushIndex->Begin();
frameData.pushVertex->Begin();
render_->BeginPushBuffer(frameData.pushIndex);
render_->BeginPushBuffer(frameData.pushVertex);
}
void DrawEngineGLES::EndFrame() {
FrameData &frameData = frameData_[render_->GetCurFrame()];
frameData.pushIndex->End();
frameData.pushVertex->End();
render_->EndPushBuffer(frameData.pushIndex);
render_->EndPushBuffer(frameData.pushVertex);
tessDataTransfer->EndFrame();
}
+7 -6
View File
@@ -118,8 +118,10 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
}
GPU_GLES::~GPU_GLES() {
GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
render->Wipe();
if (draw_) {
GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
render->Wipe();
}
// If we're here during app shutdown (exiting the Windows app in-game, for example)
// everything should already be cleared since DeviceLost has been run.
@@ -135,9 +137,6 @@ GPU_GLES::~GPU_GLES() {
shaderManagerGL_ = nullptr;
delete framebufferManagerGL_;
delete textureCacheGL_;
#ifdef _WIN32
gfxCtx_->SwapInterval(0);
#endif
}
static constexpr int MakeIntelSimpleVer(int v1, int v2, int v3) {
@@ -332,11 +331,13 @@ void GPU_GLES::DeviceLost() {
// TransformDraw has registered as a GfxResourceHolder.
drawEngine_.ClearInputLayoutMap();
shaderManagerGL_->ClearCache(false);
textureCacheGL_->Clear(false);
textureCacheGL_->DeviceLost();
fragmentTestCache_.Clear(false);
depalShaderCache_.Clear();
drawEngine_.DeviceLost();
framebufferManagerGL_->DeviceLost();
// Don't even try to access the lost device.
draw_ = nullptr;
}
void GPU_GLES::DeviceRestore() {
+21 -1
View File
@@ -53,6 +53,7 @@ TextureCacheGLES::TextureCacheGLES(Draw::DrawContext *draw)
SetupTextureDecoder();
nextTexture_ = nullptr;
std::vector<GLRInputLayout::Entry> entries;
entries.push_back({ 0, 3, GL_FLOAT, GL_FALSE, 20, 0 });
entries.push_back({ 1, 2, GL_FLOAT, GL_FALSE, 20, 12 });
@@ -60,7 +61,9 @@ TextureCacheGLES::TextureCacheGLES(Draw::DrawContext *draw)
}
TextureCacheGLES::~TextureCacheGLES() {
render_->DeleteInputLayout(shadeInputLayout_);
if (shadeInputLayout_) {
render_->DeleteInputLayout(shadeInputLayout_);
}
Clear(true);
}
@@ -839,6 +842,23 @@ bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level)
#endif
}
void TextureCacheGLES::DeviceLost() {
if (shadeInputLayout_) {
render_->DeleteInputLayout(shadeInputLayout_);
shadeInputLayout_ = nullptr;
}
Clear(false);
draw_ = nullptr;
render_ = nullptr;
}
void TextureCacheGLES::DeviceRestore(Draw::DrawContext *draw) {
draw_ = draw;
render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
if (!shadeInputLayout_) {
std::vector<GLRInputLayout::Entry> entries;
entries.push_back({ 0, 3, GL_FLOAT, GL_FALSE, 20, 0 });
entries.push_back({ 1, 2, GL_FLOAT, GL_FALSE, 20, 12 });
shadeInputLayout_ = render_->CreateInputLayout(entries);
}
}
+2 -1
View File
@@ -66,6 +66,7 @@ public:
void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight);
bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) override;
void DeviceLost();
void DeviceRestore(Draw::DrawContext *draw);
protected:
@@ -95,7 +96,7 @@ private:
ShaderManagerGLES *shaderManager_;
DrawEngineGLES *drawEngine_;
GLRInputLayout *shadeInputLayout_;
GLRInputLayout *shadeInputLayout_ = nullptr;
enum { INVALID_TEX = -1 };
};
+11 -3
View File
@@ -85,8 +85,9 @@ void WindowsGLContext::Resume() {
void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenum type,
GLuint id, GLenum severity, const char *msg) {
char sourceStr[32];
const char *sourceFmt = "UNDEFINED(0x%04X)";
const char *sourceFmt;
switch(source) {
case GL_DEBUG_SOURCE_API_ARB: sourceFmt = "API"; break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: sourceFmt = "WINDOW_SYSTEM"; break;
@@ -94,11 +95,12 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: sourceFmt = "THIRD_PARTY"; break;
case GL_DEBUG_SOURCE_APPLICATION_ARB: sourceFmt = "APPLICATION"; break;
case GL_DEBUG_SOURCE_OTHER_ARB: sourceFmt = "OTHER"; break;
default: sourceFmt = "UNDEFINED(0x%04X)"; break;
}
snprintf(sourceStr, sizeof(sourceStr), sourceFmt, source);
char typeStr[32];
const char *typeFmt = "UNDEFINED(0x%04X)";
const char *typeFmt;
switch(type) {
case GL_DEBUG_TYPE_ERROR_ARB: typeFmt = "ERROR"; break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: typeFmt = "DEPRECATED_BEHAVIOR"; break;
@@ -106,15 +108,17 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu
case GL_DEBUG_TYPE_PORTABILITY_ARB: typeFmt = "PORTABILITY"; break;
case GL_DEBUG_TYPE_PERFORMANCE_ARB: typeFmt = "PERFORMANCE"; break;
case GL_DEBUG_TYPE_OTHER_ARB: typeFmt = "OTHER"; break;
default: typeFmt = "UNDEFINED(0x%04X)"; break;
}
snprintf(typeStr, sizeof(typeStr), typeFmt, type);
char severityStr[32];
const char *severityFmt = "UNDEFINED";
const char *severityFmt;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH_ARB: severityFmt = "HIGH"; break;
case GL_DEBUG_SEVERITY_MEDIUM_ARB: severityFmt = "MEDIUM"; break;
case GL_DEBUG_SEVERITY_LOW_ARB: severityFmt = "LOW"; break;
default: severityFmt = "UNDEFINED(%d)"; break;
}
snprintf(severityStr, sizeof(severityStr), severityFmt, severity);
@@ -123,6 +127,10 @@ void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenu
void DebugCallbackARB(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar *message, GLvoid *userParam) {
// Ignore buffer mapping messages from NVIDIA
if (source == GL_DEBUG_SOURCE_API_ARB && type == GL_DEBUG_TYPE_OTHER_ARB && id == 131185)
return;
(void)length;
FILE *outFile = (FILE *)userParam;
char finalMessage[1024];
+18 -8
View File
@@ -13,7 +13,13 @@
#define VLOG(...)
#endif
void GLDeleter::Perform() {
// Runs on the GPU thread.
void GLDeleter::Perform(GLRenderManager *renderManager) {
for (auto pushBuffer : pushBuffers) {
renderManager->UnregisterPushBuffer(pushBuffer);
delete pushBuffer;
}
pushBuffers.clear();
for (auto shader : shaders) {
delete shader;
}
@@ -52,7 +58,7 @@ GLRenderManager::~GLRenderManager() {
_assert_(frameData_[i].deleter_prev.IsEmpty());
}
// Was anything deleted during shutdown?
deleter_.Perform();
deleter_.Perform(this);
_assert_(deleter_.IsEmpty());
}
@@ -98,15 +104,15 @@ void GLRenderManager::ThreadEnd() {
// Good point to run all the deleters to get rid of leftover objects.
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
frameData_[i].deleter.Perform();
frameData_[i].deleter_prev.Perform();
frameData_[i].deleter.Perform(this);
frameData_[i].deleter_prev.Perform(this);
for (int j = 0; j < (int)frameData_[i].steps.size(); j++) {
delete frameData_[i].steps[j];
}
frameData_[i].steps.clear();
frameData_[i].initSteps.clear();
}
deleter_.Perform();
deleter_.Perform(this);
for (int i = 0; i < (int)steps_.size(); i++) {
delete steps_[i];
@@ -140,7 +146,7 @@ bool GLRenderManager::ThreadFrame() {
}
VLOG("PULL: Setting frame[%d].readyForRun = false", threadFrame_);
frameData.readyForRun = false;
frameData.deleter_prev.Perform();
frameData.deleter_prev.Perform(this);
frameData.deleter_prev.Take(frameData.deleter);
// Previously we had a quick exit here that avoided calling Run() if run_ was suddenly false,
// but that created a race condition where frames could end up not finished properly on resize etc.
@@ -568,7 +574,7 @@ GLPushBuffer::GLPushBuffer(GLRenderManager *render, GLuint target, size_t size)
}
GLPushBuffer::~GLPushBuffer() {
assert(buffers_.empty());
Destroy();
}
void GLPushBuffer::Map() {
@@ -638,13 +644,17 @@ bool GLPushBuffer::AddBuffer() {
return true;
}
// Executed on the render thread!
void GLPushBuffer::Destroy() {
for (BufInfo &info : buffers_) {
// This will automatically unmap device memory, if needed.
render_->DeleteBuffer(info.buffer);
// NOTE: We immediately delete the buffer, don't go through the deleter, since we're on the render thread.
// render_->DeleteBuffer(info.buffer);
delete info.buffer;
FreeAlignedMemory(info.localMemory);
}
buffers_.clear();
buf_ = -1;
}
void GLPushBuffer::NextBuffer(size_t minSize) {
+163 -131
View File
@@ -177,6 +177,131 @@ private:
bool hasStorage_ = false;
};
class GLRenderManager;
// Similar to VulkanPushBuffer but is currently less efficient - it collects all the data in
// RAM then does a big memcpy/buffer upload at the end of the frame. This is at least a lot
// faster than the hundreds of buffer uploads or memory array buffers we used before.
// On modern GL we could avoid the copy using glBufferStorage but not sure it's worth the
// trouble.
// We need to manage the lifetime of this together with the other resources so its destructor
// runs on the render thread.
class GLPushBuffer {
public:
friend class GLRenderManager;
struct BufInfo {
GLRBuffer *buffer = nullptr;
uint8_t *localMemory = nullptr;
uint8_t *deviceMemory = nullptr;
size_t flushOffset = 0;
};
GLPushBuffer(GLRenderManager *render, GLuint target, size_t size);
~GLPushBuffer();
void Reset() { offset_ = 0; }
private:
// Needs context in case of defragment.
void Begin() {
buf_ = 0;
offset_ = 0;
// Note: we must defrag because some buffers may be smaller than size_.
Defragment();
Map();
assert(writePtr_);
}
void BeginNoReset() {
Map();
}
void End() {
Unmap();
}
public:
void Map();
void Unmap();
// When using the returned memory, make sure to bind the returned vkbuf.
// This will later allow for handling overflow correctly.
size_t Allocate(size_t numBytes, GLRBuffer **vkbuf) {
size_t out = offset_;
if (offset_ + ((numBytes + 3) & ~3) >= size_) {
NextBuffer(numBytes);
out = offset_;
offset_ += (numBytes + 3) & ~3;
} else {
offset_ += (numBytes + 3) & ~3; // Round up to 4 bytes.
}
*vkbuf = buffers_[buf_].buffer;
return out;
}
// Returns the offset that should be used when binding this buffer to get this data.
size_t Push(const void *data, size_t size, GLRBuffer **vkbuf) {
assert(writePtr_);
size_t off = Allocate(size, vkbuf);
memcpy(writePtr_ + off, data, size);
return off;
}
uint32_t PushAligned(const void *data, size_t size, int align, GLRBuffer **vkbuf) {
assert(writePtr_);
offset_ = (offset_ + align - 1) & ~(align - 1);
size_t off = Allocate(size, vkbuf);
memcpy(writePtr_ + off, data, size);
return (uint32_t)off;
}
size_t GetOffset() const {
return offset_;
}
// "Zero-copy" variant - you can write the data directly as you compute it.
// Recommended.
void *Push(size_t size, uint32_t *bindOffset, GLRBuffer **vkbuf) {
assert(writePtr_);
size_t off = Allocate(size, vkbuf);
*bindOffset = (uint32_t)off;
return writePtr_ + off;
}
void *PushAligned(size_t size, uint32_t *bindOffset, GLRBuffer **vkbuf, int align) {
assert(writePtr_);
offset_ = (offset_ + align - 1) & ~(align - 1);
size_t off = Allocate(size, vkbuf);
*bindOffset = (uint32_t)off;
return writePtr_ + off;
}
size_t GetTotalSize() const;
void Flush();
protected:
void MapDevice(GLBufferStrategy strategy);
void UnmapDevice();
private:
bool AddBuffer();
void NextBuffer(size_t minSize);
void Defragment();
void Destroy();
GLRenderManager *render_;
std::vector<BufInfo> buffers_;
size_t buf_ = 0;
size_t offset_ = 0;
size_t size_ = 0;
uint8_t *writePtr_ = nullptr;
GLuint target_;
GLBufferStrategy strategy_ = GLBufferStrategy::SUBDATA;
friend class GLRenderManager;
};
enum class GLRRunType {
END,
SYNC,
@@ -184,10 +309,10 @@ enum class GLRRunType {
class GLDeleter {
public:
void Perform();
void Perform(GLRenderManager *renderManager);
bool IsEmpty() const {
return shaders.empty() && programs.empty() && buffers.empty() && textures.empty() && inputLayouts.empty() && framebuffers.empty();
return shaders.empty() && programs.empty() && buffers.empty() && textures.empty() && inputLayouts.empty() && framebuffers.empty() && pushBuffers.empty();
}
void Take(GLDeleter &other) {
_assert_msg_(G3D, IsEmpty(), "Deleter already has stuff");
@@ -197,12 +322,14 @@ public:
textures = std::move(other.textures);
inputLayouts = std::move(other.inputLayouts);
framebuffers = std::move(other.framebuffers);
pushBuffers = std::move(other.pushBuffers);
other.shaders.clear();
other.programs.clear();
other.buffers.clear();
other.textures.clear();
other.inputLayouts.clear();
other.framebuffers.clear();
other.pushBuffers.clear();
}
std::vector<GLRShader *> shaders;
@@ -211,6 +338,7 @@ public:
std::vector<GLRTexture *> textures;
std::vector<GLRInputLayout *> inputLayouts;
std::vector<GLRFramebuffer *> framebuffers;
std::vector<GLPushBuffer *> pushBuffers;
};
class GLRInputLayout {
@@ -327,6 +455,12 @@ public:
return step.create_input_layout.inputLayout;
}
GLPushBuffer *CreatePushBuffer(int frame, GLuint target, size_t size) {
GLPushBuffer *push = new GLPushBuffer(this, target, size);
RegisterPushBuffer(frame, push);
return push;
}
void DeleteShader(GLRShader *shader) {
deleter_.shaders.push_back(shader);
}
@@ -345,6 +479,17 @@ public:
void DeleteFramebuffer(GLRFramebuffer *framebuffer) {
deleter_.framebuffers.push_back(framebuffer);
}
void DeletePushBuffer(GLPushBuffer *pushbuffer) {
deleter_.pushBuffers.push_back(pushbuffer);
}
void BeginPushBuffer(GLPushBuffer *pushbuffer) {
pushbuffer->Begin();
}
void EndPushBuffer(GLPushBuffer *pushbuffer) {
pushbuffer->End();
}
void BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil);
void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment);
@@ -679,16 +824,16 @@ public:
queueRunner_.Resize(width, height);
}
// When using legacy functionality for push buffers (glBufferData), we need to flush them
// before actually making the glDraw* calls. It's best if the render manager handles that.
void RegisterPushBuffer(int frame, GLPushBuffer *buffer) {
frameData_[frame].activePushBuffers.insert(buffer);
}
void UnregisterPushBuffer(int frame, GLPushBuffer *buffer) {
auto iter = frameData_[frame].activePushBuffers.find(buffer);
_assert_(iter != frameData_[frame].activePushBuffers.end());
frameData_[frame].activePushBuffers.erase(iter);
void UnregisterPushBuffer(GLPushBuffer *buffer) {
bool found = false;
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
auto iter = frameData_[i].activePushBuffers.find(buffer);
if (iter != frameData_[i].activePushBuffers.end()) {
frameData_[i].activePushBuffers.erase(iter);
found = true;
}
}
assert(found);
}
void SetSwapFunction(std::function<void()> swapFunction) {
@@ -726,6 +871,12 @@ private:
void FlushSync();
void EndSyncFrame(int frame);
// When using legacy functionality for push buffers (glBufferData), we need to flush them
// before actually making the glDraw* calls. It's best if the render manager handles that.
void RegisterPushBuffer(int frame, GLPushBuffer *buffer) {
frameData_[frame].activePushBuffers.insert(buffer);
}
// Per-frame data, round-robin so we can overlap submission with execution of the previous frame.
struct FrameData {
std::mutex push_mutex;
@@ -788,122 +939,3 @@ private:
int targetWidth_ = 0;
int targetHeight_ = 0;
};
// Similar to VulkanPushBuffer but is currently less efficient - it collects all the data in
// RAM then does a big memcpy/buffer upload at the end of the frame. This is at least a lot
// faster than the hundreds of buffer uploads or memory array buffers we used before.
// On modern GL we could avoid the copy using glBufferStorage but not sure it's worth the
// trouble.
class GLPushBuffer {
public:
struct BufInfo {
GLRBuffer *buffer = nullptr;
uint8_t *localMemory = nullptr;
uint8_t *deviceMemory = nullptr;
size_t flushOffset = 0;
};
public:
GLPushBuffer(GLRenderManager *render, GLuint target, size_t size);
~GLPushBuffer();
void Destroy();
void Reset() { offset_ = 0; }
// Needs context in case of defragment.
void Begin() {
buf_ = 0;
offset_ = 0;
// Note: we must defrag because some buffers may be smaller than size_.
Defragment();
Map();
assert(writePtr_);
}
void BeginNoReset() {
Map();
}
void End() {
Unmap();
}
void Map();
void Unmap();
// When using the returned memory, make sure to bind the returned vkbuf.
// This will later allow for handling overflow correctly.
size_t Allocate(size_t numBytes, GLRBuffer **vkbuf) {
size_t out = offset_;
if (offset_ + ((numBytes + 3) & ~3) >= size_) {
NextBuffer(numBytes);
out = offset_;
offset_ += (numBytes + 3) & ~3;
} else {
offset_ += (numBytes + 3) & ~3; // Round up to 4 bytes.
}
*vkbuf = buffers_[buf_].buffer;
return out;
}
// Returns the offset that should be used when binding this buffer to get this data.
size_t Push(const void *data, size_t size, GLRBuffer **vkbuf) {
assert(writePtr_);
size_t off = Allocate(size, vkbuf);
memcpy(writePtr_ + off, data, size);
return off;
}
uint32_t PushAligned(const void *data, size_t size, int align, GLRBuffer **vkbuf) {
assert(writePtr_);
offset_ = (offset_ + align - 1) & ~(align - 1);
size_t off = Allocate(size, vkbuf);
memcpy(writePtr_ + off, data, size);
return (uint32_t)off;
}
size_t GetOffset() const {
return offset_;
}
// "Zero-copy" variant - you can write the data directly as you compute it.
// Recommended.
void *Push(size_t size, uint32_t *bindOffset, GLRBuffer **vkbuf) {
assert(writePtr_);
size_t off = Allocate(size, vkbuf);
*bindOffset = (uint32_t)off;
return writePtr_ + off;
}
void *PushAligned(size_t size, uint32_t *bindOffset, GLRBuffer **vkbuf, int align) {
assert(writePtr_);
offset_ = (offset_ + align - 1) & ~(align - 1);
size_t off = Allocate(size, vkbuf);
*bindOffset = (uint32_t)off;
return writePtr_ + off;
}
size_t GetTotalSize() const;
void Flush();
protected:
void MapDevice(GLBufferStrategy strategy);
void UnmapDevice();
private:
bool AddBuffer();
void NextBuffer(size_t minSize);
void Defragment();
GLRenderManager *render_;
std::vector<BufInfo> buffers_;
size_t buf_ = 0;
size_t offset_ = 0;
size_t size_ = 0;
uint8_t *writePtr_ = nullptr;
GLuint target_;
GLBufferStrategy strategy_ = GLBufferStrategy::SUBDATA;
friend class GLRenderManager;
};
+4 -7
View File
@@ -523,17 +523,14 @@ OpenGLContext::OpenGLContext() {
break;
}
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
frameData_[i].push = new GLPushBuffer(&renderManager_, GL_ARRAY_BUFFER, 64 * 1024);
renderManager_.RegisterPushBuffer(i, frameData_[i].push);
frameData_[i].push = renderManager_.CreatePushBuffer(i, GL_ARRAY_BUFFER, 64 * 1024);
}
}
OpenGLContext::~OpenGLContext() {
DestroyPresets();
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
renderManager_.UnregisterPushBuffer(i, frameData_[i].push);
frameData_[i].push->Destroy();
delete frameData_[i].push;
renderManager_.DeletePushBuffer(frameData_[i].push);
}
boundSamplers_.clear();
}
@@ -541,12 +538,12 @@ OpenGLContext::~OpenGLContext() {
void OpenGLContext::BeginFrame() {
renderManager_.BeginFrame();
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
frameData.push->Begin();
renderManager_.BeginPushBuffer(frameData.push);
}
void OpenGLContext::EndFrame() {
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
frameData.push->End(); // upload the data!
renderManager_.EndPushBuffer(frameData.push); // upload the data!
renderManager_.Finish();
}