[2.3] Rendersystem _setTexture issues (porting imgui) Topic is solved

Problems building or running the engine, queries about how to use features etc.
Post Reply
vian
Gnoblar
Posts: 3
Joined: Wed Jul 27, 2022 8:20 pm

[2.3] Rendersystem _setTexture issues (porting imgui)

Post by vian »

Ogre Version: :2.3.0:
Operating System: :Windows 11:
Render System: :OpenGL:

I am attempting to use Imgui with Ogre 2.3, and I was able to port existing code supporting Ogre 2.1 (from https://gitlab.com/edherbert/southsea/- ... /ImguiOgre) however everything except the font renders.

Image

I suspect that the issue is triggered by:

Code: Select all

mSceneMgr->getDestinationRenderSystem()->_setTexture(0, (Ogre::TextureGpu*)drawCmd->TextureId, false);

due to the fact that the font texture is correctly loaded in RenderDoc, and another user porting imgui had an issue regarding this line of code:
viewtopic.php?p=544400#p544400

Here are some other imgui porting threads that I found that might help:

I am unsure how to proceed and correct this issue, I would greatly appreciate any help and feedback.

Here are my modified files:

ImguiManager.cpp

Code: Select all

#include "ImguiManager.h"

#include <CommandBuffer/OgreCbDrawCall.h>
//#include <OgreHardwarePixelBuffer.h>
#include <Compositor/OgreCompositorWorkspace.h>
#include <Compositor/Pass/OgreCompositorPass.h>
#include <OgreHighLevelGpuProgramManager.h>
#include <OgreHlmsDatablock.h>
#include <OgreMaterialManager.h>
#include <OgrePass.h>
#include <OgrePsoCacheHelper.h>
#include <OgreRenderSystem.h>
#include <OgreRoot.h>
#include <OgreSceneManager.h>
#include <OgreTechnique.h>
#include <OgreTextureBox.h>
#include <OgreTextureGpuManager.h>
#include <OgreUnifiedHighLevelGpuProgram.h>
#include <OgreViewport.h>
#include <SDL.h>

#include "FontCousine_Regular.h"
//#include "System/Setup/SystemSettings.h"

#ifdef _WIN32
//#include <OgreD3D11Device.h>
//#include <OgreD3D11RenderSystem.h>
#endif

template <>
ImguiManager* Ogre::Singleton<ImguiManager>::msSingleton = 0;

ImguiManager* ImguiManager::getSingletonPtr(void) {
    if (!msSingleton) {
        msSingleton = new ImguiManager();
    }
    return msSingleton;
}
ImguiManager& ImguiManager::getSingleton(void) {
    if (!msSingleton) {
        msSingleton = new ImguiManager();
    }
    return (*msSingleton);
}

ImguiManager::ImguiManager() : mSceneMgr(0),
                               mLastRenderedFrame(4),
                               mFrameEnded(true) {
}
ImguiManager::~ImguiManager() {
    // delete mPSOCache;
}

void ImguiManager::shutdown() {
    while (mRenderables.size() > 0) {
        delete mRenderables.back();
        mRenderables.pop_back();
    }
    // Ogre::TextureManager::getSingleton().remove(mFontTex);
    delete mPSOCache;

std::string name = mSceneMgr->getDestinationRenderSystem()->getName();
if (name == "Direct3D11 Rendering Subsystem") {
    // This seems to me to be a work around.
    // For some reason I was seeing assert failures when trying to destroy manual materials, OgreD3D11DeviceResource.cpp, line 59, it was checking if the device resources were empty.
    // There was however the manual texture left over.
    // This was the way I found to get rid of it.
    // mFontTex->~Texture();
}
}

void ImguiManager::init(Ogre::CompositorWorkspace* compositor) {
    mSceneMgr = compositor->getSceneManager();
    mCompositor = compositor;

mPSOCache = new Ogre::PsoCacheHelper(mSceneMgr->getDestinationRenderSystem());

createFontTexture();
createMaterial();
}

void ImguiManager::newFrame() {
    mFrameEnded = false;
    ImGuiIO& io = ImGui::GetIO();

static Uint64 g_Time = 0;
static Uint64 frequency = SDL_GetPerformanceFrequency();
Uint64 current_time = SDL_GetPerformanceCounter();
io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
g_Time = current_time;

// just some defaults so it doesn't crash
float width = 400.f;
float height = 400.f;

// might not exist if this got called before the rendering loop
Ogre::TextureGpu* renderTarget = mCompositor->getFinalTarget();
if (renderTarget) {
    width = renderTarget->getWidth();
    height = renderTarget->getHeight();
}

// Setup display size (every frame to accommodate for window resizing)
io.DisplaySize = ImVec2(width, height);

// Start the frame
ImGui::NewFrame();

// bool show_demo_window;
// ImGui::ShowDemoWindow(&show_demo_window);
}

void ImguiManager::updateProjectionMatrix(float width, float height) {
    Ogre::Matrix4 projMatrix(2.0f / width, 0.0f, 0.0f, -1.0f,
                             0.0f, -2.0f / height, 0.0f, 1.0f,
                             0.0f, 0.0f, -1.0f, 0.0f,
                             0.0f, 0.0f, 0.0f, 1.0f);

mPass->getVertexProgramParameters()->setNamedConstant("ProjectionMatrix", projMatrix);

ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(width, height);
}

void ImguiManager::render() {
#ifdef __APPLE__
    @autoreleasepool {
#endif

    Ogre::RenderSystem* renderSystem = mSceneMgr->getDestinationRenderSystem();

    if (!renderPassDesc) {
        renderPassDesc = renderSystem->createRenderPassDescriptor();
        renderPassDesc->mColour[0].texture = mCompositor->getFinalTarget();
        renderPassDesc->mColour[0].loadAction = Ogre::LoadAction::Load;
        renderPassDesc->mColour[0].storeAction = Ogre::StoreAction::StoreOrResolve;
        renderPassDesc->entriesModified(Ogre::RenderPassDescriptor::All);
    }
    Ogre::Vector4 viewportSize(0, 0, 1, 1);
    Ogre::Vector4 scissors(0, 0, 1, 1);
    renderSystem->beginRenderPassDescriptor(renderPassDesc, mCompositor->getFinalTarget(), 0, &viewportSize, &scissors, 1, false, false);
    renderSystem->executeRenderPassDescriptorDelayedActions();

    // Cancel rendering if not necessary
    // or if newFrame didn't got called
    if (mFrameEnded)
        return;
    mFrameEnded = true;

    int currentFrame = ImGui::GetFrameCount();
    if (currentFrame == mLastRenderedFrame) {
        return;
    }
    mLastRenderedFrame = currentFrame;

    // Tell ImGui to create the buffers
    ImGui::Render();

    ImGuiIO& io = ImGui::GetIO();
    if (currentFrame < 5) {
        // Update the matrix for the first few frames, to make sure everything's synchronised.
        updateProjectionMatrix(io.DisplaySize.x, io.DisplaySize.y);
    }
    if (currentFrame <= 1) {
        // Lots of stuff can be done only once for the sake of efficiency.

        mPSOCache->clearState();

        mPSOCache->setRenderTarget(renderPassDesc);  // dark_sylinc's advice on setting rendertarget, which looks like the renderwindow obj)

        const Ogre::HlmsBlendblock* blendblock = mPass->getBlendblock();
        const Ogre::HlmsMacroblock* macroblock = mPass->getMacroblock();
        mPSOCache->setMacroblock(macroblock);
        mPSOCache->setBlendblock(blendblock);
        mPSOCache->setVertexShader(const_cast<Ogre::GpuProgramPtr&>(mPass->getVertexProgram()));
        mPSOCache->setPixelShader(const_cast<Ogre::GpuProgramPtr&>(mPass->getFragmentProgram()));
    }

    ImDrawData* drawData = ImGui::GetDrawData();
    int numberDraws = 0;

    int vpWidth = mCompositor->getFinalTarget()->getWidth();
    int vpHeight = mCompositor->getFinalTarget()->getHeight();

    // iterate through all lists (at the moment every window has its own)
    for (int n = 0; n < drawData->CmdListsCount; n++) {
        const ImDrawList* drawList = drawData->CmdLists[n];
        const ImDrawVert* vtxBuf = drawList->VtxBuffer.Data;
        const ImDrawIdx* idxBuf = drawList->IdxBuffer.Data;

        unsigned int startIdx = 0;

        for (int i = 0; i < drawList->CmdBuffer.Size; i++) {
            // create renderables if necessary
            // This creates a new one each time it notices the list is bigger than necessary.
            if (i >= mRenderables.size()) {
                mRenderables.push_back(new ImguiRenderable());
            }

            // update their vertex buffers
            const ImDrawCmd* drawCmd = &drawList->CmdBuffer[i];
            mRenderables[i]->updateVertexData(vtxBuf, &idxBuf[startIdx], drawList->VtxBuffer.Size, drawCmd->ElemCount);

            // Set scissoring
            int scLeft = static_cast<int>(drawCmd->ClipRect.x);  // Obtain bounds
            int scTop = static_cast<int>(drawCmd->ClipRect.y);
            int scRight = static_cast<int>(drawCmd->ClipRect.z);
            int scBottom = static_cast<int>(drawCmd->ClipRect.w);

            scLeft = scLeft < 0 ? 0 : (scLeft > vpWidth ? vpWidth : scLeft);  // Clamp bounds to viewport dimensions
            scRight = scRight < 0 ? 0 : (scRight > vpWidth ? vpWidth : scRight);
            scTop = scTop < 0 ? 0 : (scTop > vpHeight ? vpHeight : scTop);
            scBottom = scBottom < 0 ? 0 : (scBottom > vpHeight ? vpHeight : scBottom);

            float left = (float)scLeft / (float)vpWidth;
            float top = (float)scTop / (float)vpHeight;
            float width = (float)(scRight - scLeft) / (float)vpWidth;
            float height = (float)(scBottom - scTop) / (float)vpHeight;

            scissors = Ogre::Vector4(left, top, width, height);
            renderSystem->beginRenderPassDescriptor(renderPassDesc, mCompositor->getFinalTarget(), 0, &viewportSize, &scissors, 1, false, false);
            renderSystem->executeRenderPassDescriptorDelayedActions();

            Ogre::v1::RenderOperation renderOp;
            mRenderables[i]->getRenderOperation(renderOp, false);

            bool enablePrimitiveRestart = true;  // tried both true and false...no change

            Ogre::VertexElement2VecVec vertexElements = renderOp.vertexData->vertexDeclaration->convertToV2();
            mPSOCache->setVertexFormat(vertexElements,
                                       renderOp.operationType,
                                       enablePrimitiveRestart);

            Ogre::HlmsPso* pso = mPSOCache->getPso();
            mSceneMgr->getDestinationRenderSystem()->_setPipelineStateObject(pso);

            mSceneMgr->getDestinationRenderSystem()->bindGpuProgramParameters(Ogre::GPT_VERTEX_PROGRAM, mPass->getVertexProgramParameters(), Ogre::GPV_ALL);

            mSceneMgr->getDestinationRenderSystem()->_setTexture(0, (Ogre::TextureGpu*)drawCmd->TextureId, false);

            Ogre::v1::CbRenderOp op(renderOp);
            mSceneMgr->getDestinationRenderSystem()->_setRenderOperation(&op);

            mSceneMgr->getDestinationRenderSystem()->_render(renderOp);

            // increase start index of indexbuffer
            startIdx += drawCmd->ElemCount;
            numberDraws++;
        }
    }

    // reset Scissors
    // vp->setScissors(0, 0, 1, 1);
    // TODO: uncommented //mSceneMgr->getDestinationRenderSystem()->_setViewport(vp);

    // delete unused renderables
    while (mRenderables.size() > numberDraws) {
        delete mRenderables.back();
        mRenderables.pop_back();
    }

    renderSystem->endRenderPassDescriptor();
#ifdef __APPLE__
    }
#endif
}

void ImguiManager::createMaterial() {
    static const char* vertexShaderSrcD3D11 =
        {
            "uniform float4x4 ProjectionMatrix;\n"
            "struct VS_INPUT\n"
            "{\n"
            "float2 pos : POSITION;\n"
            "float4 col : COLOR0;\n"
            "float2 uv  : TEXCOORD0;\n"
            "};\n"
            "struct PS_INPUT\n"
            "{\n"
            "float4 pos : SV_POSITION;\n"
            "float4 col : COLOR0;\n"
            "float2 uv  : TEXCOORD0;\n"
            "};\n"
            "PS_INPUT main(VS_INPUT input)\n"
            "{\n"
            "PS_INPUT output;\n"
            "output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\n"
            "output.col = input.col;\n"
            "output.uv  = input.uv;\n"
            "return output;\n"
            "}"};
    static const char* pixelShaderSrcD3D11 =
        {
            "struct PS_INPUT\n"
            "{\n"
            "float4 pos : SV_POSITION;\n"
            "float4 col : COLOR0;\n"
            "float2 uv  : TEXCOORD0;\n"
            "};\n"
            "sampler sampler0: register(s0);\n"
            "Texture2D texture0: register(t0);\n"
            "\n"
            "float4 main(PS_INPUT input) : SV_Target\n"
            "{\n"
            "float4 out_col = input.col; /* * texture0.Sample(sampler0, input.uv); */\n"
            "return out_col; \n"
            "}"};

static const char* vertexShaderSrcGLSL =
    {
        "#version 150\n"
        "uniform mat4 ProjectionMatrix; \n"
        "in vec2 vertex;\n"
        "in vec2 uv0;\n"
        "in vec4 colour;\n"
        "out vec2 Texcoord;\n"
        "out vec4 col;\n"
        "void main()\n"
        "{\n"
        "gl_Position = ProjectionMatrix* vec4(vertex.xy, 0.f, 1.f);\n"
        "Texcoord  = uv0;\n"
        "col = colour;\n"
        "}"};
static const char* pixelShaderSrcGLSL =
    {
        "#version 150\n"
        "in vec2 Texcoord;\n"
        "in vec4 col;\n"
        "uniform sampler2D sampler0;\n"
        "out vec4 out_col;\n"
        "void main()\n"
        "{\n"
        "out_col = col; /* * texture(sampler0, Texcoord);*/\n"
        "}"};

static const char* fragmentShaderSrcMetal =
    {
        "#include <metal_stdlib>\n"
        "using namespace metal;\n"
        "\n"
        "struct VertexOut {\n"
        "    float4 position [[position]];\n"
        "    float2 texCoords;\n"
        "    float4 colour;\n"
        "};\n"
        "\n"
        "fragment float4 main_metal(VertexOut in [[stage_in]],\n"
        "                             texture2d<float> texture [[texture(0)]]) {\n"
        "    constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n"
        "    float4 texColour = texture.sample(linearSampler, in.texCoords);\n"
        "    return in.colour; /* * texColour;*/\n"
        "}\n"};

static const char* vertexShaderSrcMetal =
    {
        "#include <metal_stdlib>\n"
        "using namespace metal;\n"
        "\n"
        "struct Constant {\n"
        "    float4x4 ProjectionMatrix;\n"
        "};\n"
        "\n"
        "struct VertexIn {\n"
        "    float2 position  [[attribute(VES_POSITION)]];\n"
        "    float2 texCoords [[attribute(VES_TEXTURE_COORDINATES0)]];\n"
        "    float4 colour     [[attribute(VES_DIFFUSE)]];\n"
        "};\n"
        "\n"
        "struct VertexOut {\n"
        "    float4 position [[position]];\n"
        "    float2 texCoords;\n"
        "    float4 colour;\n"
        "};\n"
        "\n"
        "vertex VertexOut vertex_main(VertexIn in                 [[stage_in]],\n"
        "                             constant Constant &uniforms [[buffer(PARAMETER_SLOT)]]) {\n"
        "    VertexOut out;\n"
        "    out.position = uniforms.ProjectionMatrix * float4(in.position, 0, 1);\n"

        "    out.texCoords = in.texCoords;\n"
        "    out.colour = in.colour;\n"

        "    return out;\n"
        "}\n"};

// create the default shadows material
Ogre::HighLevelGpuProgramManager& mgr = Ogre::HighLevelGpuProgramManager::getSingleton();

Ogre::HighLevelGpuProgramPtr vertexShaderUnified = mgr.getByName("imgui/VP");
Ogre::HighLevelGpuProgramPtr pixelShaderUnified = mgr.getByName("imgui/FP");

Ogre::HighLevelGpuProgramPtr vertexShaderD3D11 = mgr.getByName("imgui/VP/D3D11");
Ogre::HighLevelGpuProgramPtr pixelShaderD3D11 = mgr.getByName("imgui/FP/D3D11");

Ogre::HighLevelGpuProgramPtr vertexShaderGL = mgr.getByName("imgui/VP/GL150");
Ogre::HighLevelGpuProgramPtr pixelShaderGL = mgr.getByName("imgui/FP/GL150");

Ogre::HighLevelGpuProgramPtr vertexShaderMetal = mgr.getByName("imgui/VP/Metal");
Ogre::HighLevelGpuProgramPtr pixelShaderMetal = mgr.getByName("imgui/FP/Metal");

if (vertexShaderUnified.isNull()) {
    vertexShaderUnified = mgr.createProgram("imgui/VP", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "unified", Ogre::GPT_VERTEX_PROGRAM);
}
if (pixelShaderUnified.isNull()) {
    pixelShaderUnified = mgr.createProgram("imgui/FP", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "unified", Ogre::GPT_FRAGMENT_PROGRAM);
}

Ogre::UnifiedHighLevelGpuProgram* vertexShaderPtr = static_cast<Ogre::UnifiedHighLevelGpuProgram*>(vertexShaderUnified.get());
Ogre::UnifiedHighLevelGpuProgram* pixelShaderPtr = static_cast<Ogre::UnifiedHighLevelGpuProgram*>(pixelShaderUnified.get());

if (vertexShaderD3D11.isNull()) {
    vertexShaderD3D11 = mgr.createProgram("imgui/VP/D3D11", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                          "hlsl", Ogre::GPT_VERTEX_PROGRAM);
    vertexShaderD3D11->setParameter("target", "vs_4_0");
    vertexShaderD3D11->setParameter("entry_point", "main");
    vertexShaderD3D11->setSource(vertexShaderSrcD3D11);
    vertexShaderD3D11->load();

    vertexShaderPtr->addDelegateProgram(vertexShaderD3D11->getName());
}
if (pixelShaderD3D11.isNull()) {
    pixelShaderD3D11 = mgr.createProgram("imgui/FP/D3D11", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                         "hlsl", Ogre::GPT_FRAGMENT_PROGRAM);
    pixelShaderD3D11->setParameter("target", "ps_4_0");
    pixelShaderD3D11->setParameter("entry_point", "main");
    pixelShaderD3D11->setSource(pixelShaderSrcD3D11);
    pixelShaderD3D11->load();

    pixelShaderPtr->addDelegateProgram(pixelShaderD3D11->getName());
}

if (vertexShaderMetal.isNull()) {
    vertexShaderMetal = mgr.createProgram("imgui/VP/Metal", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                          "metal", Ogre::GPT_VERTEX_PROGRAM);
    vertexShaderMetal->setParameter("entry_point", "vertex_main");
    vertexShaderMetal->setSource(vertexShaderSrcMetal);
    vertexShaderMetal->load();
    vertexShaderPtr->addDelegateProgram(vertexShaderMetal->getName());
}
if (pixelShaderMetal.isNull()) {
    pixelShaderMetal = mgr.createProgram("imgui/FP/Metal", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                         "metal", Ogre::GPT_FRAGMENT_PROGRAM);
    vertexShaderMetal->setParameter("entry_point", "fragment_main");
    pixelShaderMetal->setSource(fragmentShaderSrcMetal);
    pixelShaderMetal->load();
    pixelShaderPtr->addDelegateProgram(pixelShaderMetal->getName());
}

if (vertexShaderGL.isNull()) {
    vertexShaderGL = mgr.createProgram("imgui/VP/GL150", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                       "glsl", Ogre::GPT_VERTEX_PROGRAM);
    vertexShaderGL->setSource(vertexShaderSrcGLSL);
    vertexShaderGL->load();
    vertexShaderPtr->addDelegateProgram(vertexShaderGL->getName());
}
if (pixelShaderGL.isNull()) {
    pixelShaderGL = mgr.createProgram("imgui/FP/GL150", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                      "glsl", Ogre::GPT_FRAGMENT_PROGRAM);
    pixelShaderGL->setSource(pixelShaderSrcGLSL);
    pixelShaderGL->load();
    pixelShaderGL->setParameter("sampler0", "int 0");

    pixelShaderPtr->addDelegateProgram(pixelShaderGL->getName());
}

Ogre::MaterialPtr imguiMaterial = Ogre::MaterialManager::getSingleton().create("imgui/material", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
mPass = imguiMaterial->getTechnique(0)->getPass(0);
mPass->setFragmentProgram("imgui/FP");
mPass->setVertexProgram("imgui/VP");

Ogre::HlmsBlendblock blendblock(*mPass->getBlendblock());
blendblock.mSourceBlendFactor = Ogre::SBF_SOURCE_ALPHA;
blendblock.mDestBlendFactor = Ogre::SBF_ONE_MINUS_SOURCE_ALPHA;
blendblock.mSourceBlendFactorAlpha = Ogre::SBF_ONE_MINUS_SOURCE_ALPHA;
blendblock.mDestBlendFactorAlpha = Ogre::SBF_ZERO;
blendblock.mBlendOperation = Ogre::SBO_ADD;
blendblock.mBlendOperationAlpha = Ogre::SBO_ADD;
blendblock.mSeparateBlend = true;
blendblock.mIsTransparent = true;

Ogre::HlmsMacroblock macroblock(*mPass->getMacroblock());
macroblock.mCullMode = Ogre::CULL_NONE;
macroblock.mDepthFunc = Ogre::CMPF_ALWAYS_PASS;
macroblock.mDepthCheck = false;
macroblock.mDepthWrite = false;
macroblock.mScissorTestEnabled = true;

mPass->setBlendblock(blendblock);
mPass->setMacroblock(macroblock);

Ogre::String renderSystemName = mSceneMgr->getDestinationRenderSystem()->getName();
// Apparently opengl was the only one that needed this.
if (renderSystemName == "OpenGL 3+ Rendering Subsystem") {
    mPass->getFragmentProgramParameters()->setNamedConstant("sampler0", 0);
}
mPass->createTextureUnitState()->setTexture(mFontTex);
}

void ImguiManager::createFontTexture() {
    // Build texture atlas
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();
    unsigned char* pixels;
    int width, height;

// Use the default font if there is no content scaling because it looks better.
float guiScale = 1;  // Southsea::SystemSettings::getGuiScale();
if (guiScale >= 2.0f) {
    // 13 being the default font size.
    ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(MyFont_compressed_data_base85, (int)(guiScale * 13));
#ifdef __APPLE__
        // This is a work around for macOS.
        // Currently the only way I've found to represent high-res fonts with the metal renderer is to do this.
        // My theory is that this is something to do with my metal imgui implementation, but I haven't found the cause yet.
        font->Scale = guiScale;
#endif
    } else {
        io.Fonts->AddFontDefault();
    }
    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);

Ogre::TextureGpuManager* textureManager = mSceneMgr->getDestinationRenderSystem()->getTextureGpuManager();

mFontTex = textureManager->createTexture("ImguiFontTex", Ogre::GpuPageOutStrategy::AlwaysKeepSystemRamCopy, Ogre::TextureFlags::AutomaticBatching, Ogre::TextureTypes::Type2D);
// Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, width, height, 1, 1, Ogre::PF_R8G8B8A8
mFontTex->setPixelFormat(Ogre::PixelFormatGpu::PFG_RGBA8_UINT);
mFontTex->setResolution(width, height);

io.Fonts->SetTexID(mFontTex);

Ogre::Image2 image;

int sizeInBytes = width * height * 4;
Ogre::uint8* data = reinterpret_cast<Ogre::uint8*>(OGRE_MALLOC_SIMD(sizeInBytes, Ogre::MEMCATEGORY_GENERAL));
image.loadDynamicImage(data, width, height, 1u, Ogre::TextureTypes::Type2D, mFontTex->getPixelFormat(), true, 1U);
memcpy(data, pixels, sizeInBytes);

bool canUseSynchronousUpload =
    mFontTex->getNextResidencyStatus() == Ogre::GpuResidency::Resident &&
    mFontTex->isDataReady();
if (canUseSynchronousUpload) {
    // If canUseSynchronousUpload is false, you can use areaTex->waitForData()
    // to still use sync method (assuming the texture is resident)
    image.uploadTo(mFontTex, 0, mFontTex->getNumMipmaps() - 1u);
} else {
    // Asynchronous is preferred due to being done in the background. But the switch
    // Resident -> OnStorage -> Resident may cause undesired effects, so we
    // show how to do it synchronously

    // Tweak via _setAutoDelete so the internal data is copied as a pointer
    // instead of performing a deep copy of the data; while leaving the responsability
    // of freeing memory to imagePtr instead.
    image._setAutoDelete(false);
    Ogre::Image2* imagePtr = new Ogre::Image2(image);
    imagePtr->_setAutoDelete(true);

    if (mFontTex->getNextResidencyStatus() == Ogre::GpuResidency::Resident)
        mFontTex->scheduleTransitionTo(Ogre::GpuResidency::OnStorage);
    // Ogre will call "delete imagePtr" when done, because we're passing
    // true to autoDeleteImage argument in scheduleTransitionTo
    mFontTex->scheduleTransitionTo(Ogre::GpuResidency::Resident, imagePtr, true);
}

// mFontTex->getBuffer()->lock(Ogre::Image::Box(0, 0, width, height), Ogre::v1::HardwareBuffer::HBL_DISCARD);
// size_t texDepth = Ogre::PixelUtil::getNumElemBytes(lockBox.format);

// mFontTex->getBuffer()->unlock();
}

ImguiManager.h

Code: Select all

#pragma once

#include "imgui.h"
#include "ImguiRenderable.h"

#include <OgreSingleton.h>
#include <OgreTextureGpu.h>
#include <OgreFastArray.h>
#include <OgreFrameListener.h>
#include <OgreRenderPassDescriptor.h>


namespace Ogre{
	class PsoCacheHelper;
}

class SceneManager;

class ImguiManager : public Ogre::Singleton < ImguiManager >
{
public:
	ImguiManager();
	~ImguiManager();

//call once before using ImGui
void init(Ogre::CompositorWorkspace* compositor);

//call every frame before using any Imgui functions
void newFrame();
//call at the end of the frame, the gui gets rendered inside of this function
void render();

void updateProjectionMatrix(float width, float height);

void shutdown();


/** Override standard Singleton retrieval.
@remarks
Why do we do this? Well, it's because the Singleton
implementation is in a .h file, which means it gets compiled
into anybody who includes it. This is needed for the
Singleton template to work, but we actually only want it
compiled into the implementation of the class based on the
Singleton, not all of them. If we don't change this, we get
link errors when trying to use the Singleton-based class from
an outside dll.
@par
This method just delegates to the template version anyway,
but the implementation stays in this single compilation unit,
preventing link errors.
*/
static ImguiManager& getSingleton(void);
/** Override standard Singleton retrieval.
@remarks
Why do we do this? Well, it's because the Singleton
implementation is in a .h file, which means it gets compiled
into anybody who includes it. This is needed for the
Singleton template to work, but we actually only want it
compiled into the implementation of the class based on the
Singleton, not all of them. If we don't change this, we get
link errors when trying to use the Singleton-based class from
an outside dll.
@par
This method just delegates to the template version anyway,
but the implementation stays in this single compilation unit,
preventing link errors.
*/
static ImguiManager* getSingletonPtr(void);

private:
	void createFontTexture();
	void createMaterial();

Ogre::FastArray<ImguiRenderable*> mRenderables;

Ogre::PsoCacheHelper* mPSOCache;

Ogre::SceneManager *mSceneMgr;

Ogre::Pass *mPass;
Ogre::TextureGpu *mFontTex;

int mLastRenderedFrame;
bool mFrameEnded;

Ogre::CompositorWorkspace *mCompositor;

Ogre::RenderPassDescriptor *renderPassDesc = nullptr;
};

Thank you!

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4957
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1154
Contact:

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by dark_sylinc »

The bug will often boil down to two possibilities:

  1. Texture is wrong. This is easy to verify, by looking the binding in RenderDoc. The right texture must be bound.
  2. The alpha blending setting is wrong. This is in the Pipeline State -> FB. Alpha blending must be enabled with the right blending modes.

If the alpha blend is wrong, then either the macroblock or the PSO is incorrect.

vian
Gnoblar
Posts: 3
Joined: Wed Jul 27, 2022 8:20 pm

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by vian »

From RenderDoc It seems that the correct texture is bound, and the alpha blending modes align to other working imgui ports from earlier ogre versions.

I changed the font texture (TextureGpu object) to load a dark png file from the filesystem to see if there would be any visible change, but the screen still displays white rectangles.

In RenderDoc when I go to the resource inspector and click on the texture "_InternalTex2" I see its contents align with the created texture, however the section "Usage in Frame" appears to be empty.

If the texture is bound, why would it not appear in the frame?

Last edited by vian on Thu Jul 28, 2022 10:56 pm, edited 2 times in total.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4957
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1154
Contact:

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by dark_sylinc »

Can you upload somewhere (e.g. Mega, Dropbox, GDrive) a (zipped) capture so I can take a quick look?

vian
Gnoblar
Posts: 3
Joined: Wed Jul 27, 2022 8:20 pm

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by vian »

Last edited by vian on Fri Jul 29, 2022 1:50 am, edited 1 time in total.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4957
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1154
Contact:

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by dark_sylinc »

OK I took a quick look and the shader never samples any texture:

Checking out the code you provided, the texture sampling is commented out:

Code: Select all

static const char* pixelShaderSrcGLSL =
    {
        "#version 150\n"
        "in vec2 Texcoord;\n"
        "in vec4 col;\n"
        "uniform sampler2D sampler0;\n"
        "out vec4 out_col;\n"
        "void main()\n"
        "{\n"
        "out_col = col; /* * texture(sampler0, Texcoord);*/\n" // -----------> HERE
        "}"};
vian
Gnoblar
Posts: 3
Joined: Wed Jul 27, 2022 8:20 pm

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by vian »

That is a good point. However, I commented that out because the texture is not displayed even with that line, and the Imgui window appears grayed out.

Image

Here is a capture with that line uncommented:

I tried changing

Code: Select all

mPass->getFragmentProgramParameters()->setNamedConstant("sampler0", 0);

to

Code: Select all

mPass->getFragmentProgramParameters()->setNamedConstant("sampler0", mPass->getNumTextureUnitStates());

in case there were other texture units, however mPass->getNumTextureUnitStates() returns 0 so that does not seem to be the problem.

Last edited by vian on Sat Jul 30, 2022 11:26 pm, edited 2 times in total.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4957
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1154
Contact:

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by dark_sylinc »

Ok NOW the texture is not being bound.

I see this snippet sets the texture

Code: Select all

mSceneMgr->getDestinationRenderSystem()->_setTexture( 0, (Ogre::TextureGpu *)drawCmd->TextureId, false );

However I can't see where drawCmd->TextureId comes from. Or that it's a valid TextureGpu \*. I suspect it's created by ImGui, if that's so I highly doubt that pointer is a TextureGpu*

I can also see this call:

Code: Select all

mPass->createTextureUnitState()->setTexture( mFontTex );

However this isn't enough because this compositor pass is rendering stuff by hand, thus I don't think this call is actually doing anything.

vian
Gnoblar
Posts: 3
Joined: Wed Jul 27, 2022 8:20 pm

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by vian »

drawCmd->TextureId is a void pointer that is set with

Code: Select all

io.Fonts->SetTexID(mFontTex);

and is identical to mFontTex
Image

I agree with your assessment. It seems like mPass is not being used except for its parameters and thus its TextureUnit is not used.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4957
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1154
Contact:

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by dark_sylinc »

AHHH!!! I think I figured it out!

The texture was created with AutomaticBatching.
This means internally the texture is of type sampler2DArray, not sampler2D.

Try creating the texture with "0" in texture flags, instead of AutomaticBatching.

Update: I also just caught the format is PFG_RGBA8_UINT. It should be PFG_RGBA8_UNORM.

vian
Gnoblar
Posts: 3
Joined: Wed Jul 27, 2022 8:20 pm

Re: [2.3] Rendersystem _setTexture issues (porting imgui)

Post by vian »

It looks like that solved the problem!

Thanks a lot for your help.

Post Reply