#pragma once #include #include #include #include #include "Common/GPU/OpenGL/GLCommon.h" #include "Common/Data/Collections/Hashmaps.h" #include "Common/GPU/thin3d.h" class GLRShader; class GLRBuffer; class GLRTexture; class GLRInputLayout; class GLRFramebuffer; class GLPushBuffer; class GLRProgram; class GLRenderManager; class GLDeleter { public: void Perform(GLRenderManager *renderManager, bool skipGLCalls); bool IsEmpty() const { return shaders.empty() && programs.empty() && buffers.empty() && textures.empty() && inputLayouts.empty() && framebuffers.empty() && pushBuffers.empty(); } void Take(GLDeleter &other); std::vector shaders; std::vector programs; std::vector buffers; std::vector textures; std::vector inputLayouts; std::vector framebuffers; std::vector pushBuffers; }; // TODO: To be safe, should probably add some more stuff here, like format and even readback count, maybe. struct GLReadbackKey { const GLRFramebuffer *framebuf; Draw::DataFormat dstFormat; int width; int height; }; struct GLCachedReadback { GLuint buffer; // PBO size_t bufferSize; // pending data uint8_t *data; size_t dataSize; bool pending; bool convert; void Destroy(bool skipGLCalls); }; // These are transformed to GLCachedReadback at the end of the frame. struct GLQueuedReadback { }; // Per-frame data, round-robin so we can overlap submission with execution of the previous frame. struct GLFrameData { GLFrameData() : readbacks_(8) {} bool skipSwap = false; std::mutex fenceMutex; std::condition_variable fenceCondVar; bool readyForFence = true; // Swapchain. bool hasBegun = false; GLDeleter deleter; GLDeleter deleter_prev; std::set activePushBuffers; std::mutex readbackMutex; DenseHashMap readbacks_; std::vector queuedReadbacks_; void PerformReadbacks(); void EndFrame(); void Destroy(bool skipGLCalls); };