// // GLBackend.h // libraries/gpu/src/gpu // // Created by Sam Gateau on 10/27/2014. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #ifndef hifi_gpu_gl_GLBackend_h #define hifi_gpu_gl_GLBackend_h #include #include #include #include #include #include #include #include #include #include #include #include "GLShared.h" namespace gpu { namespace gl { class GLBackend : public Backend { // Context Backend static interface required friend class gpu::Context; static void init(); static Backend* createBackend(); static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings); protected: explicit GLBackend(bool syncCache); GLBackend(); public: ~GLBackend(); void render(Batch& batch) final; // This call synchronize the Full Backend cache with the current GLState // THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync // the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls // Let's try to avoid to do that as much as possible! void syncCache() final; // This is the ugly "download the pixels to sysmem for taking a snapshot" // Just avoid using it, it's ugly and will break performances virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) final; static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; static const int MAX_NUM_INPUT_BUFFERS = 16; size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); } // this is the maximum per shader stage on the low end apple // TODO make it platform dependant at init time static const int MAX_NUM_UNIFORM_BUFFERS = 12; size_t getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; } // this is the maximum per shader stage on the low end apple // TODO make it platform dependant at init time static const int MAX_NUM_RESOURCE_TEXTURES = 16; size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } // Draw Stage virtual void do_draw(Batch& batch, size_t paramOffset) = 0; virtual void do_drawIndexed(Batch& batch, size_t paramOffset) = 0; virtual void do_drawInstanced(Batch& batch, size_t paramOffset) = 0; virtual void do_drawIndexedInstanced(Batch& batch, size_t paramOffset) = 0; virtual void do_multiDrawIndirect(Batch& batch, size_t paramOffset) = 0; virtual void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) = 0; // Input Stage virtual void do_setInputFormat(Batch& batch, size_t paramOffset) final; virtual void do_setInputBuffer(Batch& batch, size_t paramOffset) final; virtual void do_setIndexBuffer(Batch& batch, size_t paramOffset) final; virtual void do_setIndirectBuffer(Batch& batch, size_t paramOffset) final; virtual void do_generateTextureMips(Batch& batch, size_t paramOffset) final; // Transform Stage virtual void do_setModelTransform(Batch& batch, size_t paramOffset) final; virtual void do_setViewTransform(Batch& batch, size_t paramOffset) final; virtual void do_setProjectionTransform(Batch& batch, size_t paramOffset) final; virtual void do_setViewportTransform(Batch& batch, size_t paramOffset) final; virtual void do_setDepthRangeTransform(Batch& batch, size_t paramOffset) final; // Uniform Stage virtual void do_setUniformBuffer(Batch& batch, size_t paramOffset) final; // Resource Stage virtual void do_setResourceTexture(Batch& batch, size_t paramOffset) final; // Pipeline Stage virtual void do_setPipeline(Batch& batch, size_t paramOffset) final; // Output stage virtual void do_setFramebuffer(Batch& batch, size_t paramOffset) final; virtual void do_clearFramebuffer(Batch& batch, size_t paramOffset) final; virtual void do_blit(Batch& batch, size_t paramOffset) = 0; // Query section virtual void do_beginQuery(Batch& batch, size_t paramOffset) final; virtual void do_endQuery(Batch& batch, size_t paramOffset) final; virtual void do_getQuery(Batch& batch, size_t paramOffset) final; // Reset stages virtual void do_resetStages(Batch& batch, size_t paramOffset) final; virtual void do_runLambda(Batch& batch, size_t paramOffset) final; virtual void do_startNamedCall(Batch& batch, size_t paramOffset) final; virtual void do_stopNamedCall(Batch& batch, size_t paramOffset) final; virtual void do_pushProfileRange(Batch& batch, size_t paramOffset) final; virtual void do_popProfileRange(Batch& batch, size_t paramOffset) final; // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API virtual void do_glActiveBindTexture(Batch& batch, size_t paramOffset) final; virtual void do_glUniform1i(Batch& batch, size_t paramOffset) final; virtual void do_glUniform1f(Batch& batch, size_t paramOffset) final; virtual void do_glUniform2f(Batch& batch, size_t paramOffset) final; virtual void do_glUniform3f(Batch& batch, size_t paramOffset) final; virtual void do_glUniform4f(Batch& batch, size_t paramOffset) final; virtual void do_glUniform3fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniform4fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniform4iv(Batch& batch, size_t paramOffset) final; virtual void do_glUniformMatrix3fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) final; virtual void do_glColor4f(Batch& batch, size_t paramOffset) final; // The State setters called by the GLState::Commands when a new state is assigned virtual void do_setStateFillMode(int32 mode) final; virtual void do_setStateCullMode(int32 mode) final; virtual void do_setStateFrontFaceClockwise(bool isClockwise) final; virtual void do_setStateDepthClampEnable(bool enable) final; virtual void do_setStateScissorEnable(bool enable) final; virtual void do_setStateMultisampleEnable(bool enable) final; virtual void do_setStateAntialiasedLineEnable(bool enable) final; virtual void do_setStateDepthBias(Vec2 bias) final; virtual void do_setStateDepthTest(State::DepthTest test) final; virtual void do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest) final; virtual void do_setStateAlphaToCoverageEnable(bool enable) final; virtual void do_setStateSampleMask(uint32 mask) final; virtual void do_setStateBlend(State::BlendFunction blendFunction) final; virtual void do_setStateColorWriteMask(uint32 mask) final; virtual void do_setStateBlendFactor(Batch& batch, size_t paramOffset) final; virtual void do_setStateScissorRect(Batch& batch, size_t paramOffset) final; protected: virtual GLuint getFramebufferID(const FramebufferPointer& framebuffer) = 0; virtual GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) = 0; virtual GLuint getBufferID(const Buffer& buffer) = 0; virtual GLBuffer* syncGPUObject(const Buffer& buffer) = 0; virtual GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) = 0; virtual GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) = 0; virtual GLuint getQueryID(const QueryPointer& query) = 0; virtual GLQuery* syncGPUObject(const Query& query) = 0; static const size_t INVALID_OFFSET = (size_t)-1; bool _inRenderTransferPass { false }; int32_t _uboAlignment { 0 }; int _currentDraw { -1 }; void renderPassTransfer(Batch& batch); void renderPassDraw(Batch& batch); void setupStereoSide(int side); virtual void initInput() final; virtual void killInput() final; virtual void syncInputStateCache() final; virtual void resetInputStage() final; virtual void updateInput(); struct InputStageState { bool _invalidFormat { true }; Stream::FormatPointer _format; typedef std::bitset ActivationCache; ActivationCache _attributeActivation { 0 }; typedef std::bitset BuffersState; BuffersState _invalidBuffers { 0 }; Buffers _buffers; Offsets _bufferOffsets; Offsets _bufferStrides; std::vector _bufferVBOs; glm::vec4 _colorAttribute{ 0.0f }; BufferPointer _indexBuffer; Offset _indexBufferOffset { 0 }; Type _indexBufferType { UINT32 }; BufferPointer _indirectBuffer; Offset _indirectBufferOffset{ 0 }; Offset _indirectBufferStride{ 0 }; GLuint _defaultVAO { 0 }; InputStageState() : _buffers(_invalidBuffers.size()), _bufferOffsets(_invalidBuffers.size(), 0), _bufferStrides(_invalidBuffers.size(), 0), _bufferVBOs(_invalidBuffers.size(), 0) {} } _input; virtual void initTransform() = 0; void killTransform(); // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncTransformStateCache(); void updateTransform(const Batch& batch); void resetTransformStage(); struct TransformStageState { using CameraBufferElement = TransformCamera; using TransformCameras = std::vector; TransformCamera _camera; TransformCameras _cameras; mutable std::map _drawCallInfoOffsets; GLuint _objectBuffer { 0 }; GLuint _cameraBuffer { 0 }; GLuint _drawCallInfoBuffer { 0 }; GLuint _objectBufferTexture { 0 }; size_t _cameraUboSize { 0 }; Transform _view; Mat4 _projection; Vec4i _viewport { 0, 0, 1, 1 }; Vec2 _depthRange { 0.0f, 1.0f }; bool _invalidView { false }; bool _invalidProj { false }; bool _invalidViewport { false }; using Pair = std::pair; using List = std::list; List _cameraOffsets; mutable List::const_iterator _camerasItr; mutable size_t _currentCameraOffset{ INVALID_OFFSET }; void preUpdate(size_t commandIndex, const StereoState& stereo); void update(size_t commandIndex, const StereoState& stereo) const; void bindCurrentCamera(int stereoSide) const; } _transform; virtual void transferTransformState(const Batch& batch) const = 0; struct UniformStageState { std::array _buffers; //Buffers _buffers { }; } _uniform; void releaseUniformBuffer(uint32_t slot); void resetUniformStage(); // update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s void releaseResourceTexture(uint32_t slot); void resetResourceStage(); struct ResourceStageState { std::array _textures; //Textures _textures { { MAX_NUM_RESOURCE_TEXTURES } }; int findEmptyTextureSlot() const; } _resource; size_t _commandIndex{ 0 }; // Standard update pipeline check that the current Program and current State or good to go for a void updatePipeline(); // Force to reset all the state fields indicated by the 'toBeReset" signature void resetPipelineState(State::Signature toBeReset); // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncPipelineStateCache(); void resetPipelineStage(); struct PipelineStageState { PipelinePointer _pipeline; GLuint _program { 0 }; GLShader* _programShader { nullptr }; bool _invalidProgram { false }; State::Data _stateCache { State::DEFAULT }; State::Signature _stateSignatureCache { 0 }; GLState* _state { nullptr }; bool _invalidState { false }; } _pipeline; // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncOutputStateCache(); void resetOutputStage(); struct OutputStageState { FramebufferPointer _framebuffer { nullptr }; GLuint _drawFBO { 0 }; } _output; void resetQueryStage(); struct QueryStageState { }; void resetStages(); typedef void (GLBackend::*CommandCall)(Batch&, size_t); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; friend class GLState; }; } } #endif