HifiExperimentsalways cache samplers70aa1f61 year agoHistory
340 lines · 11.2 KB · C++
RawDownload
////  GLBackendPipeline.cpp//  libraries/gpu/src/gpu////  Created by Sam Gateau on 3/8/2015.//  Copyright 2014 High Fidelity, Inc.//  Copyright 2024 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//#include "GLBackend.h"#include <gpu/TextureTable.h>#include <gpu/ShaderConstants.h> #include "GLShared.h"#include "GLPipeline.h"#include "GLShader.h"#include "GLState.h"#include "GLBuffer.h"#include "GLTexture.h" using namespace gpu;using namespace gpu::gl; void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {    const auto& pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint);     if (compare(_pipeline._pipeline, pipeline)) {        return;    }     // A true new Pipeline    _stats._PSNumSetPipelines++;     // null pipeline == reset    if (!pipeline) {        reset(_pipeline._pipeline);         _pipeline._program = 0;        _pipeline._programShader = nullptr;        _pipeline._invalidProgram = true;         _pipeline._state = nullptr;        _pipeline._invalidState = true;    } else {        auto pipelineObject = GLPipeline::sync(*this, *pipeline);        if (!pipelineObject) {            return;        }             // check the program cache            // pick the program version            // check the program cache            // pick the program version#ifdef GPU_STEREO_CAMERA_BUFFER        GLuint glprogram = pipelineObject->_program->getProgram(getShaderVariant());#else        GLuint glprogram = pipelineObject->_program->getProgram();#endif         if (_pipeline._program != glprogram) {            _pipeline._program = glprogram;            _pipeline._programShader = pipelineObject->_program;            _pipeline._invalidProgram = true;        }         // Now for the state        if (_pipeline._state != pipelineObject->_state) {            _pipeline._state = pipelineObject->_state;            _pipeline._invalidState = true;        }         // Remember the new pipeline        assign(_pipeline._pipeline, pipeline);    }     // THis should be done on Pipeline::update...    if (_pipeline._invalidProgram) {        glUseProgram(_pipeline._program);        (void)CHECK_GL_ERROR();        _pipeline._invalidProgram = false;    }} void GLBackend::updatePipeline() {    if (_pipeline._invalidProgram) {        // doing it here is aproblem for calls to glUniform.... so will do it on assing...        glUseProgram(_pipeline._program);        (void)CHECK_GL_ERROR();        _pipeline._invalidProgram = false;    }     if (_pipeline._invalidState) {        if (_pipeline._state) {            // first reset to default what should be            // the fields which were not to default and are default now            resetPipelineState(_pipeline._state->_signature);             // Update the signature cache with what's going to be touched            _pipeline._stateSignatureCache |= _pipeline._state->_signature;             // And perform            for (const auto& command : _pipeline._state->_commands) {                command->run(this);            }        } else {            // No state ? anyway just reset everything            resetPipelineState(0);        }        _pipeline._invalidState = false;    }} void GLBackend::resetPipelineStage() {    // First reset State to default    State::Signature resetSignature(0);    resetPipelineState(resetSignature);    _pipeline._state = nullptr;    _pipeline._invalidState = false;     // Second the shader side    _pipeline._invalidProgram = false;    _pipeline._program = 0;    _pipeline._programShader = nullptr;    reset(_pipeline._pipeline);    glUseProgram(0);} void GLBackend::releaseUniformBuffer(uint32_t slot) {    auto& bufferState = _uniform._buffers[slot];    if (valid(bufferState.buffer)) {        glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0);  // RELEASE        (void)CHECK_GL_ERROR();    }    bufferState.reset();} void GLBackend::resetUniformStage() {    for (uint32_t i = 0; i < _uniform._buffers.size(); i++) {        releaseUniformBuffer(i);    }} void GLBackend::bindUniformBuffer(uint32_t slot, const BufferPointer& buffer, GLintptr offset, GLsizeiptr size) {    if (!buffer) {        releaseUniformBuffer(slot);        return;    }      auto& currentBufferState = _uniform._buffers[slot];    // check cache before thinking    if (currentBufferState.compare(buffer, offset, size)) {        return;    }     // Grab the true gl Buffer object    auto glBO = getBufferIDUnsynced(*buffer);    if (glBO) {        glBindBufferRange(GL_UNIFORM_BUFFER, slot, glBO, offset, size);        assign(currentBufferState.buffer, buffer);        currentBufferState.offset = offset;        currentBufferState.size = size;        (void)CHECK_GL_ERROR();    } else {        releaseUniformBuffer(slot);        return;    } } void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) {    GLuint slot = batch._params[paramOffset + 3]._uint;    if (slot > (GLuint)MAX_NUM_UNIFORM_BUFFERS) {        qCDebug(gpugllogging) << "GLBackend::do_setUniformBuffer: Trying to set a uniform Buffer at slot #" << slot                              << " which doesn't exist. MaxNumUniformBuffers = " << getMaxNumUniformBuffers();        return;    }     const auto& uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);    GLintptr rangeStart = batch._params[paramOffset + 1]._uint;    GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;     bindUniformBuffer(slot, uniformBuffer, rangeStart, rangeSize);} void GLBackend::releaseResourceTexture(uint32_t slot) {    auto& textureState = _resource._textures[slot];    if (valid(textureState._texture)) {        glActiveTexture(GL_TEXTURE0 + slot);        glBindTexture(textureState._target, 0);  // RELEASE        (void)CHECK_GL_ERROR();        reset(textureState._texture);    }} void GLBackend::resetResourceStage() {    uint32_t i;    for (i = 0; i < _resource._buffers.size(); i++) {        releaseResourceBuffer(i);    }    for (i = 0; i < _resource._textures.size(); i++) {        releaseResourceTexture(i);    }} void GLBackend::do_setResourceBuffer(const Batch& batch, size_t paramOffset) {    GLuint slot = batch._params[paramOffset + 1]._uint;    if (slot >= (GLuint)MAX_NUM_RESOURCE_BUFFERS) {        qCDebug(gpugllogging) << "GLBackend::do_setResourceBuffer: Trying to set a resource Buffer at slot #" << slot                              << " which doesn't exist. MaxNumResourceBuffers = " << getMaxNumResourceBuffers();        return;    }     const auto& resourceBuffer = batch._buffers.get(batch._params[paramOffset + 0]._uint);     if (!resourceBuffer) {        releaseResourceBuffer(slot);        return;    }    // check cache before thinking    if (compare(_resource._buffers[slot], resourceBuffer)) {        return;    }     // One more True Buffer bound    _stats._RSNumResourceBufferBounded++;     // If successful bind then cache it    if (bindResourceBuffer(slot, resourceBuffer)) {        assign(_resource._buffers[slot], resourceBuffer);    } else {  // else clear slot and cache        releaseResourceBuffer(slot);        return;    }} void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {    GLuint slot = batch._params[paramOffset + 1]._uint;    if (slot >= (GLuint)MAX_NUM_RESOURCE_TEXTURES) {        qCDebug(gpugllogging) << "GLBackend::do_setResourceTexture: Trying to set a resource Texture at slot #" << slot                              << " which doesn't exist. MaxNumResourceTextures = " << getMaxNumResourceTextures();        return;    }     const auto& resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);    const Sampler& sampler = batch._samplers.get(batch._params[paramOffset + 2]._uint);    bindResourceTexture(slot, resourceTexture, sampler);} void GLBackend::bindResourceTexture(uint32_t slot, const TexturePointer& resourceTexture, const Sampler& sampler) {    if (!resourceTexture) {        releaseResourceTexture(slot);        return;    }    setResourceTexture(slot, resourceTexture, sampler);} void GLBackend::do_setResourceFramebufferSwapChainTexture(const Batch& batch, size_t paramOffset) {    GLuint slot = batch._params[paramOffset + 1]._uint;    if (slot >= (GLuint)MAX_NUM_RESOURCE_TEXTURES) {        qCDebug(gpugllogging)            << "GLBackend::do_setResourceFramebufferSwapChainTexture: Trying to set a resource Texture at slot #" << slot            << " which doesn't exist. MaxNumResourceTextures = " << getMaxNumResourceTextures();        return;    }     auto swapChain =        std::static_pointer_cast<FramebufferSwapChain>(batch._swapChains.get(batch._params[paramOffset + 0]._uint));     if (!swapChain) {        releaseResourceTexture(slot);        return;    }    auto index = batch._params[paramOffset + 2]._uint;    auto renderBufferSlot = batch._params[paramOffset + 3]._uint;    const Sampler& sampler = batch._samplers.get(batch._params[paramOffset + 4]._uint);     const auto& resourceFramebuffer = swapChain->get(index);    const auto& resourceTexture = resourceFramebuffer->getRenderBuffer(renderBufferSlot);    setResourceTexture(slot, resourceTexture, sampler);} void GLBackend::setResourceTexture(unsigned int slot, const TexturePointer& resourceTexture, const Sampler& sampler) {    auto& textureState = _resource._textures[slot];    // check cache before thinking    if (compare(textureState._texture, resourceTexture) && textureState._sampler == sampler) {        return;    }     // One more True texture bound    _stats._RSNumTextureBounded++;     // Always make sure the GLObject is in sync    GLTexture* object = syncGPUObject(resourceTexture);    if (object) {        assign(textureState._texture, resourceTexture);        GLuint to = object->_texture;        textureState._target = object->_target;        textureState._sampler = sampler;        glActiveTexture(GL_TEXTURE0 + slot);        glBindTexture(textureState._target, to);        object->syncSampler(sampler);        (void)CHECK_GL_ERROR();        _stats._RSAmountTextureMemoryBounded += (uint64_t)object->size();     } else {        releaseResourceTexture(slot);        return;    }} void GLBackend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) {    const auto& textureTablePointer = batch._textureTables.get(batch._params[paramOffset]._uint);    if (!textureTablePointer) {        return;    }     GLuint startSlot = batch._params[paramOffset + 1]._uint;    size_t samplerIndex = 0;    const auto& textureTable = *textureTablePointer;    const auto& textures = textureTable.getTextures();    for (GLuint slot = 0; slot < textures.size(); ++slot) {        const auto& texture = textures[slot];        const Sampler& sampler = batch._samplers.get(batch._params[paramOffset + 2 + (samplerIndex++)]._uint);         bindResourceTexture(slot + startSlot, texture, sampler);    }} int GLBackend::ResourceStageState::findEmptyTextureSlot() const {    // start from the end of the slots, try to find an empty one that can be used    for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) {        if (!valid(_textures[i]._texture)) {            return i;        }    }    return -1;}