Renderable not showing up


#1

I’m trying to render a 2D image but nothing is showing up. Additionally I can’t find anything in RenderDoc that uses the texture as input. So I think something is preventing it from getting even sent to the graphics API. Do I need to set a bounding box or something to not have my object culled? I’m using a specific layer for the object, but even if I comment that out, it still doesn’t work. I also tried to disable culling but that also didn’t do anything.

This is my code:

    Node = bs::SceneObject::create(("View_" + std::to_string(ID)).c_str());
    Renderable = Node->addComponent<bs::CRenderable>();
    Renderable->setLayer(1 << GetScene());

    auto QuadMesh = GeometryHelpers::CreateScreenSpaceQuad(-1, -1, 2, 2);
    // auto QuadMesh = GeometryHelpers::CreateScreenSpaceQuad(0, 0, 1280, 720);

    bs::HShader shader =
        bs::gImporter().import<bs::Shader>("Data/Shaders/CoreShaders/ScreenSpaceGUI.bsl");
    // bs::gBuiltinResources().getBuiltinShader(bs::BuiltinShader::ParticlesUnlit);
    Material = bs::Material::create(shader);

    Renderable->setMesh(QuadMesh);
    Renderable->setMaterial(Material);
    // then later...
    Texture = bs::Texture::create(DataBuffer, bs::TU_DYNAMIC);
    Material->setTexture("image", Texture);

Mesh generation is here: https://github.com/hhyyrylainen/Leviathan/blob/bsf/Engine/Rendering/GeometryHelpers.cpp
Camera setup: https://github.com/hhyyrylainen/Leviathan/blob/bsf/Engine/GUI/GuiLayer.cpp#L16

And this is my shader:

options
{
    sort = backtofront;
    transparent = true;
};

shader ScreenSpaceGUI
{
    depth
    {
        write = false;
    };

    blend
    {
        target
        {
            enabled = true;
            color = { srcA, srcIA, add };
        };
    };
    
    code
    {
        struct VStoFS
        {
            float4 position : SV_Position;
            float2 uv0 : TEXCOORD0;
        };

        [alias(image)]
        SamplerState imageSampler
        {
            Filter = MIN_MAG_MIP_LINEAR;
            AddressU = Clamp;
            AddressV = Clamp;
        };
        
        Texture2D image = black;

        cbuffer PerObject
        {
             float4x4 gMatWorldViewProj;
        }

        struct VertexInput
        {
            float3 position : POSITION;
            float2 uv0 : TEXCOORD0;
        };
        
        VStoFS vsmain(VertexInput input)
        {
            VStoFS output;
        
            output.uv0 = input.uv0;
            output.position = float4(input.position, 1.f);
            return output;
        }
        
        float4 fsmain(in VStoFS input) : SV_Target0
        {
            return image.Sample(imageSampler, input.uv0);
        }   
    };
};

At this point I have no clue what the problem might be.


#2

Arbitrary shaders won’t work with the default renderer. You can either make sure your shaders comply with the rules required by the renderer, as described here: http://docs.bsframework.io/nightly/User_Manuals/Custom_Materials/surfaceShaders.html.

Or you can use low-level rendering do render everything manually: http://docs.bsframework.io/nightly/Developer_Manuals/Low_Level_rendering/drawing.html. Also check the LowLevelRendering example. You can use low-level rendering to draw to completely different surface than the renderer, or add your own low-level rendering code to the renderer through extensions (http://docs.bsframework.io/nightly/Developer_Manuals/Renderer/rendererExtensions.html).

Judging by your code, it looks like low level rendering might be more appropriate in this case.


#3

Alright. I’ll look into the low level rendering and renderer extensions. I was reading the regular manual (http://docs.bsframework.io/latest/manuals.html), so I missed all those docs about the low level rendering that was mentioned quite a few times in the manual.


#4

I’m now trying to render the mesh with a RendererExtension. I get this error:

[ERROR] A fatal error occurred and the program has to terminate!
  - Error: InvalidParametersException
  - Description: Invalid sub-mesh index (0). Number of sub-meshes available: 0
  - In function: const bs::SubMesh& bs::MeshProperties::getSubMesh(bs::UINT32) const
  - In file: /home/hhyyrylainen/Projects/Leviathan/ThirdParty/bsf/Source/Foundation/bsfCore/Mesh/BsMeshBase.cpp:32

Stack trace: 
0) /home/hhyyrylainen/Projects/Leviathan/build/bin/lib/libbsf.so.1: bs::CrashHandler::getStackTrace[abi:cxx11]()+0x1bf [0x7fffed91025f]
1) /home/hhyyrylainen/Projects/Leviathan/build/bin/lib/libbsf.so.1: bs::CrashHandler::logErrorAndStackTrace(std::__cxx11::basic_string<char, std::char_traits<char>, bs::StdAlloc<char, bs::GenAlloc> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, bs::StdAlloc<char, bs::GenAlloc> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, bs::StdAlloc<char, bs::GenAlloc> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, bs::StdAlloc<char, bs::GenAlloc> > const&, unsigned int) const+0x32b [0x7fffed8f527b]
2) /home/hhyyrylainen/Projects/Leviathan/build/bin/lib/libbsf.so.1: bs::CrashHandler::reportCrash(std::__cxx11::basic_string<char, std::char_traits<char>, bs::StdAlloc<char, bs::GenAlloc> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, bs::StdAlloc<char, bs::GenAlloc> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, bs::StdAlloc<char, bs::GenAlloc> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, bs::StdAlloc<char, bs::GenAlloc> > const&, unsigned int) const+0x9 [0x7fffed90fad9]
3) /home/hhyyrylainen/Projects/Leviathan/build/bin/lib/libbsf.so.1: bs::MeshProperties::getSubMesh(unsigned int) const+0x236 [0x7fffedcba5d6]
4) /home/hhyyrylainen/Projects/Leviathan/build/bin/lib/libbsf.so.1: bs::ct::RendererUtility::draw(std::shared_ptr<bs::ct::MeshBase> const&, unsigned int)+0x1b [0x7fffede22d5b]
5) /home/hhyyrylainen/Projects/Leviathan/build/bin/libEngine.so: Leviathan::GUIOverlayRenderer::render(bs::ct::Camera const&)+0x161 [0x7ffff7d40b91]

There are at least something in my mesh object:

$2 = (bs::ct::Mesh) {
  <bs::ct::MeshBase> = {
    <bs::ct::CoreObject> = {
      _vptr.CoreObject = 0x7fffee17c148 <vtable for bs::ct::Mesh+16>, 
      mFlags = 1 '\001', 
      mThis = std::weak_ptr<bs::ct::CoreObject> (use count 1, weak count 1) = {
        get() = 0x658f290
      }
    }, 
    members of bs::ct::MeshBase: 
    mProperties = {
      mSubMeshes = std::vector of length 0, capacity 0, 
      mNumVertices = 4, 
      mNumIndices = 6, 
      mBounds = {
        mBox = {
          mMinimum = {
            x = -0.5, 
            y = -0.5, 
            z = -0.5
          }, 
          mMaximum = {
            x = 0.5, 
            y = 0.5, 
            z = 0.5
          }
        }, 
        mSphere = {
          mRadius = 1, 
          mCenter = {
            x = 0, 
            y = 0, 
            z = 0
          }
        }
      }
    }
  }, 
  members of bs::ct::Mesh: 
  mVertexData = std::shared_ptr<bs::ct::VertexData> (use count 1, weak count 0) = {
    get() = 0x7ffee45f3900
  }, 
  mIndexBuffer = std::shared_ptr<bs::ct::IndexBuffer> (use count 1, weak count 1) = {
    get() = 0x7ffee22958f0
  }, 
  mVertexDesc = std::shared_ptr<bs::VertexDataDesc> (use count 1, weak count 0) = {
    get() = 0x6326680
  }, 
  mUsage = 1, 
  mIndexType = bs::IT_16BIT, 
  mDeviceMask = bs::GDF_DEFAULT, 
  mTempInitialMeshData = std::shared_ptr<bs::MeshData> (empty) = {
    get() = 0x0
  }, 
  mSkeleton = std::shared_ptr<bs::Skeleton> (empty) = {
    get() = 0x0
  }, 
  mMorphShapes = std::shared_ptr<bs::MorphShapes> (empty) = {
    get() = 0x0
  }
}

I assume something is wrong with my mesh generation: https://github.com/hhyyrylainen/Leviathan/blob/bsf/Engine/Rendering/GeometryHelpers.cpp#L8 or maybe I need to use a different rendering method?

Here’s my RendererExtension code: https://github.com/hhyyrylainen/Leviathan/blob/bsf/Engine/Rendering/GUIOverlayRenderer.cpp


#5

I think you just need to add an entry to MESH_DESC.subMeshes, covering your entire index range since you just have one sub-mesh.

Note that you also have RenderUtility::drawScreenQuad helper for drawing a full screen quad.


#6

Thanks. I got it working with that submesh setting. The documentation said that if I left it blank it would automatically mean that there is a single submesh covering all indices…

So it is working now. But I’m getting a bunch of random crashes like double free or corruption (!prev) and corrupted size vs. prev_size. Not sure what is up with that. Previously running in valgrind fails in the resource listener constructor.


#7

Try using a 32-bit index buffer. I don’t think I’m using 16-bit one anywhere internally which means there’s more potential for problems. Other than that I can’t tell what the issue could be.


#8

That does not seem to help. I’ll try using valgrind to see what it says.

Edit: I found the problem. I was building bsf in RelWithDebInfo mode (to skip the automatic strip step in the build, otherwise I can’t use Breakpad) and for some reason that defines DEBUG… I couldn’t find where that flag gets defined, I would have opened a pull request otherwise, but I found a bunch of places that checked for only Release when determining if to skip debug stuff.


#9

Why is the DEBUG flag an issue?


#10

Because that adds an extra member to the class:

#if BS_DEBUG_MODE
		Set<IResourceListener*> mActiveListeners;
        #error stuff here
#endif

And then when I compile my code without the debug flag the amount of memory allocated for the class is incorrect. The bs_new call is in my code and the ResourceListenerManager constructor is in bsf, so they disagree what members the class has.


#11

I found what is setting the flag. In /bsf/Source/CMake/HelperMethods.cmake
I think it is incorrect to set the DEBUG definition when building with RelWithDebInfo configuration. At least all of the other libraries, and my own, projects have exact same flags for RelWithDebInfo and Release other than generating the debug info. And only the Debug configuration enables extra code that makes the binaries incompatible.

Here’s my suggested change for that:

1 file changed, 2 insertions(+), 2 deletions(-)
Source/CMake/HelperMethods.cmake | 4 ++--

modified   Source/CMake/HelperMethods.cmake
@@ -572,7 +572,7 @@ function(add_common_flags target)
 			set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:Debug>:/Zi>)
 		endif()
 
-		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:RelWithDebInfo>:/GL /Gy /Zi /O2 /Oi /MD -DDEBUG>)
+		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:RelWithDebInfo>:/GL /Gy /Zi /O2 /Oi /MD -DNDEBUG>)
 		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:MinSizeRel>:/GL /Gy /Zi /O2 /Oi /MD -DNDEBUG>)
 		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:Release>:/GL /Gy /Zi /O2 /Oi /MD -DNDEBUG>)
 
@@ -593,7 +593,7 @@ function(add_common_flags target)
 		endif()
 
 		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:Debug>:-ggdb -O0 -DDEBUG>)
-		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:RelWithDebInfo>:-ggdb -O2 -DDEBUG -Wno-unused-variable>)
+		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:RelWithDebInfo>:-ggdb -O2 -DNDEBUG -Wno-unused-variable>)
 		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:MinSizeRel>:-ggdb -O2 -DNDEBUG -Wno-unused-variable>)
 		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS $<$<CONFIG:Release>:-ggdb -O2 -DNDEBUG -Wno-unused-variable>)

#12

We’re setting it on purpose as RelWithDebInfo is intended to be a version that is optimized yet has debug checks enabled.


#13

That does not work for me. I need a build option to build with optimizations, no debug checks and without stripped binaries.


#14

It sounds strange to me that one would require debug symbols yet not want other kind of debugging functionality as well. For example, if some render API call fails you might not get notified, and it will just silently not render or render incorrectly.

But if that is indeed the desired alternative, we could make stripping optional through a CMake flag.


#15

I use Breakpad for crash reports and that needs to have the debug symbols in the binaries (on Linux) in order to generate the debug symbol database.
So I need the release builds to contain debug symbols, otherwise crash reports from players will be missing line numbers.


#16

The way bsf is intended to be used in such case is to get an address-only call-stack from the user, and then the developer can manually map the addresses to relevant files, methods and line numbers using the separate debug symbols.

This way the user gets a nice small, lean file, and the developer can still figure out the problems.

But I understand if that is a hassle. We could add that flag to avoid stripping for such cases, feel free to open up an issue.


#17

With breakpad the user is given a pretty small dmp file that can be processed to a callstack with line numbers automatically. I even made an online tool for us to easily convert the dump files into callstacks (it doesn’t store them yet): https://dev.revolutionarygamesstudio.com/submit

Here’s an issue: https://github.com/GameFoundry/bsf/issues/337


#18

Interesting, so breakpad does it own symbol stripping? Might be nice to support that out of the box. Would that option be more preferrable, to have bsf build output breakpad symbol files directly? Or is the preferred option still to leave the symbols in and have you do that in a separate step?

(Regardless of the answer, I probably won’t have time for option #1 any time soon, but it’s good to know for future reference)


#19

Breakpad doesn’t strip the symbols. It has a tool called dump_syms that is given a path to an executable on Linux (that is not stripped) and a pdb file (if I remember correctly) on Windows, it then outputs a .sym file on stdout. That file, when placed to a certain place, can then be used by the Breakpad minidump_stackwalk tool for decoding crash dumps made by the client side breakpad library.

I have premade scripts for finding all libraries and processing them with that tool. So for me the easiest thing is that the bsf build process does nothing to the debug symbols. I can then use all my scripts as is.


#20

Sounds good.

Although the first image on this page does seem to imply there is some kind of stripping involved? https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/getting_started_with_breakpad.md Not that it matters for me at the moment.