diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 24c84b616a..b8499b50c8 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -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(); } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index ca64acae56..6fe38db384 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -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() { diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index e1b45f40c4..ae57b3b472 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -53,6 +53,7 @@ TextureCacheGLES::TextureCacheGLES(Draw::DrawContext *draw) SetupTextureDecoder(); nextTexture_ = nullptr; + std::vector 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 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); + } } diff --git a/GPU/GLES/TextureCacheGLES.h b/GPU/GLES/TextureCacheGLES.h index 36f7e600e0..a88eb8d7ec 100644 --- a/GPU/GLES/TextureCacheGLES.h +++ b/GPU/GLES/TextureCacheGLES.h @@ -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 }; }; diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index bed1349cf3..43eeaca913 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -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]; diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index d5f648b86a..da06102ccd 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -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) { diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 37279ec750..164cdc4dc4 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -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 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 shaders; @@ -211,6 +338,7 @@ public: std::vector textures; std::vector inputLayouts; std::vector framebuffers; + std::vector 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 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 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; -}; diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 84e28a2dc7..18891fded6 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -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(); }