bgfx module

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
The bgfx module will be like Cerberus opengl.openes20 module, but bgfx support Direct3D, Metal, OpenGL, and Vulkan.

More Info: https://github.com/bkaradzic/bgfx

Why implement bgfx module?

Apple is deprecating OpenGL and wants developers to use Apple's Metal library. Read https://en.wikipedia.org/wiki/MacOS_Mojave Changes section. There are no announcement about Apple dropping OpenGL on iOS, but I fear it is probably coming. Also, after OpenGL ES 3.2, developers are required to move to Vulkan. Also it will be nice to have Direct3D. Currently Direct3D in Cerberus is implemented using ANGLE, but there are apparently issues with ANGLE because of the transpiling technology. Read https://en.wikipedia.org/wiki/ANGLE_(software) Issues section.

My Plan (Updated 2 Nov 2018)

1. create bgfx.cxs (port c99\bgfx.h to Cerberus)
2. port examples to Cerberus to test bgfx.cxs (<-- currently doing this)
3. complete bgfx target (currently I use GLFW target code and comment out all the GLFW sections, it is a mess) (<-- will do this properly once the new target systems are merged into the main line)
4. try to change Mojo 2 OpenGL ES 2.0 functions call to bgfx (Not possible)
5. try to compile for other supported platforms, like Mac and iOS (will do this after number 3)
6. create Mojo 1 functions call to bgfx

Note, I will probably expand these tasks, currently these are very big tasks.
 
Last edited:

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
I am going to reserved this for future update, just in case.
 

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
How to build bgfx for Windows

The build instruction is here: https://bkaradzic.github.io/bgfx/build.html. But I got errors.

1. Cloning from github. Create a directory called byof (or whatever you like to name it), and do git clone inside that directory

git clone git://github.com/bkaradzic/bx.git
git clone git://github.com/bkaradzic/bimg.git
git clone git://github.com/bkaradzic/bgfx.git

After git clone in that director you should see 3 directories, bgfx, bimg and bx, like this:

D:\devtools\byof>dir

09/29/2018 06:56 PM <DIR> .
09/29/2018 06:56 PM <DIR> ..
09/27/2018 06:28 AM <DIR> bgfx
09/27/2018 06:21 AM <DIR> bimg
09/27/2018 06:21 AM <DIR> bx

Note bgfx + bimg + bx is >300MB

2. Downloading make.exe

Goto http://gnuwin32.sourceforge.net/packages/make.htm, download make-3.81-bin.zip
Goto http://gnuwin32.sourceforge.net/packages/coreutils.htm, download coreutils-5.3.0-bin.zip
Goto http://gnuwin32.sourceforge.net/packages/libiconv.htm, download libiconv-1.9.2-1-bin.zip
Goto http://gnuwin32.sourceforge.net/packages/libintl.htm, download libintl-0.14.4-bin.zip

Unzip and put it all into 1 directory. The finish directory should be like this:

D:\devtools\make-3.81-bin>dir

09/27/2018 03:16 AM <DIR> .
09/27/2018 03:16 AM <DIR> ..
09/27/2018 03:16 AM <DIR> bin
09/27/2018 03:16 AM <DIR> contrib
05/07/2005 06:56 PM <DIR> include
09/27/2018 03:16 AM <DIR> lib
09/27/2018 03:16 AM <DIR> man
09/27/2018 03:16 AM <DIR> manifest
09/27/2018 03:16 AM <DIR> share

3. Set path to your make, you can do this in command line SET PATH=D:\devtools\make-3.81-bin;%PATH% OR using control panel.

In Windows 7 - Control Panel -> System and Security -> System -> Advanced system settings -> Environment Variables -> System Variables -> PATH

I am not sure about Windows 10.

At this point, you can either use Mingw or VS2017.

VS2017

1. You can type one of these 4:

D:\devtools\byof\bgfx>make vs2017-debug32
D:\devtools\byof\bgfx>make vs2017-release32
D:\devtools\byof\bgfx>make vs2017-debug64
D:\devtools\byof\bgfx>make vs2017-release64

2. Open the solution in Visual Studio:

D:\devtools\byof\bgfx>start .build\projects\vs2017\bgfx.sln

3. I got an error when I try to compile. It complain it can't find malloc.h, stdlib.h. Standard C header files are not found.

If you get this error, there are 2 ways to fix it:

A. download vs_community.exe (https://docs.microsoft.com/en-us/visualstudio/install/create-an-offline-installation-of-visual-studio?view=vs-2017)

Click on the modify button.

Make sure Windows 8.1 SDK and UCRT SDK is ticked.

B. Right click on the project in the Solution Explorer and go to properties.

In the Configuration Properties -> General -> Windows SDK Version you need to change 8.1 to 10.

You need to change this for every single projects!

Mingw

1. I am using the following compilers:

32-bit: https://sourceforge.net/projects/mingw-w64/files/Toolchains targetting Win32/Personal Builds/mingw-builds/8.1.0/threads-posix/dwarf/ File: i686-8.1.0-release-posix-dwarf-rt_v6-rev0.7z

64-bit:
https://sourceforge.net/projects/mingw-w64/files/Toolchains targetting Win64/Personal Builds/mingw-builds/8.1.0/threads-posix/seh/ File: x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z

2. Open bx\scripts\toolchain.lua

I am not sure which Mingw he uses, but it did not compile for me. Look for $(MINGW). There are 4 places you need to change.

Change:

premake.gcc.cc = "$(MINGW)/bin/" .. mingwToolchain .. "-gcc"
premake.gcc.cxx = "$(MINGW)/bin/" .. mingwToolchain .. "-g++"
premake.gcc.ar = "$(MINGW)/bin/ar"

...

"$(SILENT) $(MINGW)/bin/strip -s \"$(TARGET)\""

To:

premake.gcc.cc = "D:/devtools/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/gcc"
premake.gcc.cxx = "D:/devtools/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/g++"
premake.gcc.ar = "D:/devtools/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/ar"

...

"$(SILENT) D:/devtools/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/strip -s \"$(TARGET)\""

3. Choose one:

D:\devtools\byof\bgfx>make mingw-gcc-debug32
D:\devtools\byof\bgfx>make mingw-gcc-release32 <-- this configuration the helloworld example is crashing for me
D:\devtools\byof\bgfx>make mingw-gcc-debug64
D:\devtools\byof\bgfx>make mingw-gcc-release64

Comparing Mingw vs VS2017

1. VS2017 compile time "feels" alot faster.

2. Mingw final size is 1.55GB and VS2017 size is 367MB

I think I may just start using VS2017.
 

dawlane

Active Member
CX Code Contributor
Joined
Jun 21, 2017
Took me around 20 minutes to build the lot from git. The build instructions aren't the best. You can use the GENie project configuration tool from the same author to create project build files for any of the supported tool chains.

Create a directory called bgfx and change into it.
Clone the required directories.
git clone git://github.com/bkaradzic/bx.git
git clone git://github.com/bkaradzic/bimg.git
git clone git://github.com/bkaradzic/bgfx.git

Change into the cloned bgfx
Dowload one of the GENie executables from the same author. And place it within the cloned bgfx directory.
https://github.com/bkaradzic/GENie

Use the genie application as in the docs (just type genie to see the project building options). You will find the project file within the .build directory.

The documentation for bgfx is in the wikki
https://bkaradzic.github.io/bgfx/

If you build the examples; then be warned that they will not run out of the box in the location of where the are built. You have to transfer the executable's to examples/runtime directory.

EDIT: Note if you have MinGW set to the correct location e.i C:\MinGW and the entry in the SYSTEM PATH variable set correctly to point to C:\MinGW\bin;C:\MinGW\include;C:\MinGW\lib.
TIP: Use MKLINK to create a link for C:\MinGW to point to the MinGW folder within the MinGW-w64 directory. Also note that MinGW-w64 would require the libgcc/libstdc++ and winpthread shared libraries.

Once you have the gist of how it's all put together. It shouldn't be an issue to create custom VS and makefiles for integration into a target Cerberus template the real hard bit will be making the changes to mojo to use bgfx.

The docs say that GLFW and SDL can be used for windowing systems, it's just a case of setting the context handle. I would suggest that GLFW 3.2.1 should be chosen for the task.
 
Last edited:

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
Sorry Mike, I didn't mention that I am hoping to just include header files and library files in the target, so the end user does not need to compile bgfx. But I figure I documented it here for future update. On a side note, Mingw is creating 1.5G files, I don't want the target to be copying that amount of files. We will simplify it once everything is working.

I haven't tried the genie method, something to look at.

I forgot to write about putting the example executable into examples/runtime. Did you use Mingw? If you have VS2017, you should compile with that, it is alot faster.

The docs say that GLFW and SDL can be used for windowing systems, it's just a case of setting the context handle. I would suggest that GLFW 3.2.1 should be chosen for the task.
I think we can just remove glfwMakeContextCurrent, put bgfx calls into our glfw template, and it should work. I haven't tested it though.
But the problem is, does GLFW support iOS? I think it only support Desktop. In the end we may have to create bgfx target anyway. But I will look into GLFW + iOS.

More info at: https://bkaradzic.github.io/bgfx/overview.html#sdl-glfw-etc

I am currently doing the cubes example, to get a small set of API working. I am doing the interface between Cerberus and bgfx C99. I will write about it when I get it working, because once it is written it is very hard to change. So it is best for everyone to agree now when it still can be changed.
 
Last edited:

dawlane

Active Member
CX Code Contributor
Joined
Jun 21, 2017
Mingw is creating 1.5G files
I hope you are not including the examples in that!
Building the library only using the genie generated makefiles should only produce binaries around 16meg. I've be playing around cutting down on the files that should be needed. Once I've think I've got it something; I will have to modify one or two of the examples to see if it will link and run.

I am hoping to just include header files and library files in the target
Supplying pre-built libraries should be avoid where possible, as you can never tell what version of a particular compiler the end user is going to use. It's best to create custom project build files and build from source instead.

I am doing the interface between Cerberus and bgfx C99
Caution should be used with C99 standard as it isn't fully supported with Microsoft compilers.

Did you use Mingw? If you have VS2017, you should compile with that, it is alot faster.
I always test out with MinGW and Visual Studio 2015/2017 and on Linux.

But the problem is, does GLFW support iOS? I think it only support Desktop.
Cerberus Game desktop targets always use GLFW for creating the windowing system. The other device targets have there own methods.
 

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
I build using the "make mingw-gcc-release64". That creates ~1.5G. Even the base bgfx, bimg and bx is already 300MB+, you don't want to be copying 300MB+ everytime a project is build.

Supplying pre-built libraries should be avoid where possible, as you can never tell what version of a particular compiler the end user is going to use. It's best to create custom project build files and build from source instead.
Ok, yep understand. So, we try to write a batch/shell script to make the compiling easier. I don't know, something to think about.

Caution should be used with C99 standard as it isn't fully supported with Microsoft compilers.
It is easier to read. I am more used to C then C++. I am hoping when bgfx.cxs is done, I will just change bgfx_xxx functions to bgfx::XXX, seems to be almost 1 to 1.

Cerberus Game desktop targets always use GLFW for creating the windowing system. The other device targets have there own methods.
I will see how much changes in GLFW target is required to put bgfx. If there isn't much changes may be we can use a flag like GLFW_USE_BGFX. Is using a flag a good idea? If I do make a target, Android NDK becomes an option too. Is that something of interest?
 

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
This is the code to cubes.cxs (original cpp file is at https://github.com/bkaradzic/bgfx/blob/master/examples/01-cubes/cubes.cpp)

Code:
Import mojo.app
Import bgfx

Class PosColorVertex

    Field m_x:Float
    Field m_y:Float
    Field m_z:Float
    Field m_abgr:Int

    Method New( m_x:Float, m_y:Float, m_z:Float, m_abgr:Int )
        Self.m_x = m_x
        Self.m_y = m_y
        Self.m_z = m_z
        Self.m_abgr = m_abgr
    End

    Global ms_decl:BgfxVertexDecl = New BgfxVertexDecl()

    Function Init:Void()
        bgfxVertexDeclBegin( ms_decl )
        bgfxVertexDeclAdd( ms_decl, BGFX_ATTRIB_POSITION, 3, BGFX_ATTRIB_TYPE_FLOAT )
        bgfxVertexDeclAdd( ms_decl, BGFX_ATTRIB_COLOR0, 4, BGFX_ATTRIB_TYPE_UINT8, True )
        bgfxVertexDeclEnd( ms_decl )
    End
End

Global s_cubeVertices:PosColorVertex[] = [
    New PosColorVertex( -1.0,  1.0,  1.0, $ff000000 ),
    New PosColorVertex(  1.0,  1.0,  1.0, $ff0000ff ),
    New PosColorVertex( -1.0, -1.0,  1.0, $ff00ff00 ),
    New PosColorVertex(  1.0, -1.0,  1.0, $ff00ffff ),
    New PosColorVertex( -1.0,  1.0, -1.0, $ffff0000 ),
    New PosColorVertex(  1.0,  1.0, -1.0, $ffff00ff ),
    New PosColorVertex( -1.0, -1.0, -1.0, $ffffff00 ),
    New PosColorVertex(  1.0, -1.0, -1.0, $ffffffff ) ]

Global s_cubeTriList:Int[] = [
    0, 1, 2, ' 0
    1, 3, 2,
    4, 6, 5, ' 2
    5, 6, 7,
    0, 2, 4, ' 4
    4, 2, 6,
    1, 5, 3, ' 6
    5, 7, 3,
    0, 4, 1, ' 8
    4, 5, 1,
    2, 3, 6, ' 10
    6, 3, 7]

Global s_cubeTriStrip:Int[] = [
    0, 1, 2,
    3,
    7,
    1,
    5,
    0,
    4,
    2,
    6,
    7,
    4,
    5]

Global s_cubeLineList:Int[] = [
    0, 1,
    0, 2,
    0, 4,
    1, 3,
    1, 5,
    2, 3,
    2, 6,
    3, 7,
    4, 5,
    4, 6,
    5, 7,
    6, 7]

Global s_cubePoints:Int[] = [
    0, 1, 2, 3, 4, 5, 6, 7]

Class MojoGame Extends App

    Field m_width:Int = 1280
    Field m_height:Int = 720

    Field debug:Int = BGFX_DEBUG_NONE
'      Field debug:Int = BGFX_DEBUG_TEXT

    Field sCubeVerticesBuffer:DataBuffer
    Field sCubeTriListBuffer:DataBuffer
    Field sCubeTriStripBuffer:DataBuffer
    Field sCubeLineListBuffer:DataBuffer
    Field sCubePointsBuffer:DataBuffer

    Field m_vbh:BgfxVertexBufferHandle
    Field m_ibh:BgfxIndexBufferHandle[4]
    Field m_program:BgfxProgramHandle

    Field time:Float

    Field at:Float[]  = [ 0.0, 0.0,   0.0 ]
    Field eye:Float[] = [ 0.0, 0.0, -35.0 ]

    Field bgfxCaps:BgfxCaps = New BgfxCaps()

    Field view:Float[16]
    Field proj:Float[16]
    Field mtx:Float[16]

    Method MakeDataBuffers:Void()

        Local address:Int
        Local length:Int

        ' s_cubeVertices to sCubeVerticesBuffer

        address = 0
        length = s_cubeVertices.Length()

        sCubeVerticesBuffer = New DataBuffer( length * 16 )
        For Local i:Int = 0 Until length
            sCubeVerticesBuffer.PokeFloat( address, s_cubeVertices[i].m_x ); address += 4
            sCubeVerticesBuffer.PokeFloat( address, s_cubeVertices[i].m_y ); address += 4
            sCubeVerticesBuffer.PokeFloat( address, s_cubeVertices[i].m_z ); address += 4
            sCubeVerticesBuffer.PokeInt( address, s_cubeVertices[i].m_abgr ); address += 4
        Next

        ' s_cubeTriList to sCubeTriListBuffer

        address = 0
        length = s_cubeTriList.Length()

        sCubeTriListBuffer = New DataBuffer( length * 2 )
        For Local i:Int = 0 Until length
            sCubeTriListBuffer.PokeShort( address, s_cubeTriList[i] ); address += 2
        Next

        ' s_cubeTriStrip to sCubeTriStripBuffer

        address = 0
        length = s_cubeTriStrip.Length()

        sCubeTriStripBuffer = New DataBuffer( length * 2 )
        For Local i:Int = 0 Until length
            sCubeTriStripBuffer.PokeShort( address, s_cubeTriStrip[i] ); address += 2
        Next

        ' s_cubeLineList to sCubeLineListBuffer

        address = 0
        length = s_cubeLineList.Length()

        sCubeLineListBuffer = New DataBuffer( length * 2 )
        For Local i:Int = 0 Until length
            sCubeLineListBuffer.PokeShort( address, s_cubeLineList[i] ); address += 2
        Next

        ' s_cubePoints to sCubePointsBuffer

        address = 0
        length = s_cubePoints.Length()

        sCubePointsBuffer = New DataBuffer( length * 2 )
        For Local i:Int = 0 Until length
            sCubePointsBuffer.PokeShort( address, s_cubePoints[i] ); address += 2
        Next
    End

    Method OnCreate:Int()

        SetUpdateRate(60)

        MakeDataBuffers()

        ' Enable debug text.
        bgfxSetDebug(debug)

        ' Set view 0 clear state.
        bgfxSetViewClear(0, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH, $303030ff, 1.0, 0)

        ' Create vertex stream declaration.
        PosColorVertex.Init()

        ' Create static vertex buffer.
        m_vbh = bgfxCreateVertexBuffer( bgfxMakeRef( sCubeVerticesBuffer ), PosColorVertex.ms_decl )

        ' Create static index buffer for triangle strip rendering.
        ' Static data can be passed with bgfx::makeRef
        m_ibh[0] = bgfxCreateIndexBuffer( bgfxMakeRef( sCubeTriStripBuffer ) )

        ' Create static index buffer for triangle list rendering.
        ' Static data can be passed with bgfx::makeRef
        m_ibh[1] = bgfxCreateIndexBuffer( bgfxMakeRef( sCubeTriListBuffer ) )

        ' Create static index buffer for triangle list rendering.
        ' Static data can be passed with bgfx::makeRef
        m_ibh[2] = bgfxCreateIndexBuffer( bgfxMakeRef( sCubeLineListBuffer ) )

        ' Create static index buffer for triangle list rendering.
        ' Static data can be passed with bgfx::makeRef
        m_ibh[3] = bgfxCreateIndexBuffer( bgfxMakeRef( sCubePointsBuffer ) )

        ' Create program from shaders.
        m_program = bgfxUtilsLoadProgram("vs_cubes", "fs_cubes");

        Return 0
    End

    Method OnUpdate:Int()
        time += 0.1
        Return 0
    End

    Method OnRender:Int()

        bxMtxLookAt( view, eye, at )

        bgfxGetCaps( bgfxCaps )
        bxMtxProj( proj, 60.0, Float(m_width)/Float(m_height), 0.1, 100.0, bgfxCaps.GetHomogeneousDepth() )
        bgfxSetViewTransform( 0, view, proj )

        ' Set view 0 default viewport.
        bgfxSetViewRect(0, 0, 0, m_width, m_height)

        ' This dummy draw call is here to make sure that view 0 is cleared
        ' if no other draw calls are submitted to view 0.
        bgfxTouch(0)

        ' Submit 11x11 cubes.
        For Local yy:Int = 0 Until 11
            For Local xx:Int = 0 Until 11

                bxMtxRotateXY(mtx, time + xx * 0.21, time + yy * 0.37)
'                  bxMtxRotateXY(mtx, xx * 0.21, yy * 0.37)
                mtx[12] = -15.0 + xx * 3.0
                mtx[13] = -15.0 + yy * 3.0
                mtx[14] = 0.0

                ' Set model matrix for rendering.
                bgfxSetTransform(mtx)

                ' Set vertex and index buffer.
                bgfxSetVertexBuffer(0, m_vbh)
                bgfxSetIndexBuffer(m_ibh[0])

                ' Set render states.
'                  bgfxSetState(state)
                bgfxSetState(0)

                ' Submit primitive for rendering to view 0.
                bgfxSubmit(0, m_program)
            Next
        Next

        ' Advance to next frame. Rendering thread will be kicked to
        ' process submitted rendering primitives.
        bgfxFrame(False)

        Return 0
    End

End

Function Main:Int()
    New MojoGame()
    Return 0
End
Screenshot:

cubes.png

So bgfx uses 64-bit int. Has anyone made a 64-bit int class? If not I will just make a simple version.

I need to write up the interface between C++ and Cerberus.
 

dawlane

Active Member
CX Code Contributor
Joined
Jun 21, 2017
So bgfx uses 64-bit int. Has anyone made a 64-bit int class?
You are basically stuck with a 32 bit integers across all targets.
A integer in CX is the same as the signed data type int in the back-end compilers used. The compiler vendor would determine the sizes of any data type, but they usually follow the standard the same standards as what was set out in the original 32 bit x86 compilers for backward compatibility. When compiling to 64 bit there is always bound to be some warnings at some point about the loss of precision. What matters most on a 64 bit platform is the size of a pointer, which are always going to be 64 bits wide.

For some reason, Mark Sibly; the original author of MonkeyX had a serious problem understanding why everyone kept asking for 64 bit supported versions of his software. He did actually state this back in the MonkeyX forum in one of his posts. He more than likely would have changed his mind if Microsoft had not included WOW64 in their 64 bit version of their operating systems.

EDIT:
That creates ~1.5G. Even the base bgfx, bimg and bx is already 300MB+
With MinGW-w64 7.6.2 compiling as posix 64 bit with sjsl exceptions, I'm getting around the 16-20 meg for the libbx, libbimg, libbimg_decode and libbgfx.
 
Last edited:

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
Android ndk is always of interest
Using GLFW target is also preferred for me, because all those codes (like keyboard, mouse, joystick etc) are stable. But then iOS is required, so I figure might as well create a target.

In regard to 64-bit, I will think of something to get it working.

In regard getting/compiling bgfx, my thinking right now is to modify transcc and config file to include git. So git is like mingw or VS2017 it is a tool you have to install. Then transcc can download bgfx from github + tools like genie and compile it. Just an idea.
 

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
Interface between Cerberus & C++ for bgfx

1. All enum in C++ is Int in Cerberus:

For example the enum bgfx_renderer_type_t in function bgfx_vertex_decl_begin in C++ is:

Code:
typedef enum bgfx_renderer_type
{
    BGFX_RENDERER_TYPE_NOOP,
    BGFX_RENDERER_TYPE_DIRECT3D9,
    BGFX_RENDERER_TYPE_DIRECT3D11,
    BGFX_RENDERER_TYPE_DIRECT3D12,
    BGFX_RENDERER_TYPE_GNM,
    BGFX_RENDERER_TYPE_METAL,
    BGFX_RENDERER_TYPE_OPENGLES,
    BGFX_RENDERER_TYPE_OPENGL,
    BGFX_RENDERER_TYPE_VULKAN,

    BGFX_RENDERER_TYPE_COUNT

} bgfx_renderer_type_t;

BGFX_C_API void bgfx_vertex_decl_begin(bgfx_vertex_decl_t* _decl, bgfx_renderer_type_t _renderer);
in Cerberus is: (notice _renderer is Int now)

Code:
Enumerate
    BGFX_RENDERER_TYPE_NOOP,
    BGFX_RENDERER_TYPE_DIRECT3D9,
    BGFX_RENDERER_TYPE_DIRECT3D11,
    BGFX_RENDERER_TYPE_DIRECT3D12,
    BGFX_RENDERER_TYPE_GNM,
    BGFX_RENDERER_TYPE_METAL,
    BGFX_RENDERER_TYPE_OPENGLES,
    BGFX_RENDERER_TYPE_OPENGL,
    BGFX_RENDERER_TYPE_VULKAN,

    BGFX_RENDERER_TYPE_COUNT

Function bgfxVertexDeclBegin:Void( _decl:BgfxVertexDecl, _renderer:Int=BGFX_RENDERER_TYPE_NOOP )="_bgfx_vertex_decl_begin"
2. DataBuffer vs Array (Int[] or Float[])

For example bgfxDbgTextImage: (look at the 5th argument _data)

Code:
Extern

' notice the 1st use :Int[] and the second use :DataBuffer
Function bgfxDbgTextImage:Void( _x:Int, _y:Int, _width:Int, _height:Int, _data:Int[], _pitch:Int )="_bgfx_dbg_text_image"
Function bgfxDbgTextImageDB:Void( _x:Int, _y:Int, _width:Int, _height:Int, _data:DataBuffer, _pitch:Int )="_bgfx_dbg_text_image_db"
In C++:

Code:
void _bgfx_dbg_text_image( int _x, int _y, int _width, int _height, Array<int> _data, int _pitch)
{
    // bgfx_dbg_text_image( _x, _y, _width, _height, &_data[0], _pitch);
    int len = _data.Length();
    uint8_t * data = new uint8_t[len];
    for (int i = 0 ; i < len ; i ++ )
    {
        data[i] = _data[i];
    }
    bgfx_dbg_text_image( _x, _y, _width, _height, data, _pitch);
    delete [] data;
}

void _bgfx_dbg_text_image_db( int _x, int _y, int _width, int _height, BBDataBuffer *_data, int _pitch)
{
    bgfx_dbg_text_image( _x, _y, _width, _height, _data->ReadPointer(0), _pitch);
}
The 1st function uses :Int[], and I need to convert it from 32-bit int array to 8-bit int array. There is a new and a delete (memory allocation). The 2nd uses DataBuffer and I simply just pass in a pointer, because the conversion is done in Cerberus. Also if bgfxDbgTextImage is called every frame that means you are memory allocating + copying every single frame. That's why I prefer the 2nd method, using DataBuffer.

3. All struct in C++ is wrapped in class in Cerberus:

When I was looking for example to follow, I found this in modules/mojo/audiodevice.cxs

Code:
Class Sample="gxtkSample"
    Method Discard()
End
And in mojo.glfw.cpp:

Code:
class gxtkSample : public Object{
public:
    ALuint al_buffer;

    gxtkSample();
    gxtkSample( ALuint buf );
    ~gxtkSample();
  
    void SetBuffer( ALuint buf );
  
    //***** GXTK API *****
    virtual int Discard();
};
I did something similar for bgfx struct. For example the struct bgfx_caps_t is used by function bgfx_get_caps:

Code:
typedef struct bgfx_caps_s
{
    bgfx_renderer_type_t rendererType;

    uint64_t supported;

    uint16_t vendorId;
    uint16_t deviceId;
    bool     homogeneousDepth;
    bool     originBottomLeft;
    uint8_t  numGPUs;

    bgfx_caps_gpu_t gpu[4];
    bgfx_caps_limits_t limits;

    uint16_t formats[BGFX_TEXTURE_FORMAT_COUNT];

} bgfx_caps_t;

BGFX_C_API const bgfx_caps_t* bgfx_get_caps(void);
It is wrapped as follows:

Code:
// class bgfx_caps_object wraps struct bgfx_caps_t
class bgfx_caps_object : public Object
{
    const bgfx_caps_t * _caps;

    virtual bool GetHomogeneousDepth()
    {
        return _caps->homogeneousDepth;
    }
};

void _bgfx_get_caps( bgfx_caps_object * _caps )
{
    _caps->_caps = bgfx_get_caps();
}
In Cerberus the code is like this:

Code:
Extern

Class BgfxCaps="bgfx_caps_object"
    Method GetHomogeneousDepth:Bool()
End

Function bgfxGetCaps:Void( _caps:BgfxCaps )="_bgfx_get_caps"

Public

    ' To use it:

    Field bgfxCaps:BgfxCaps = New BgfxCaps()

    Method OnRender:Int()
        bgfxGetCaps( bgfxCaps )
    End
If it is wrapped like this, it means Cerberus CAN NOT access variable unless a virtual method is created to get that variable. For example homogeneousDepth variable has the method GetHomogeneousDepth. In this example I cannot get originBottomLeft variable, unless I create the method GetOriginBottomLeft.

4. There is NO new/malloc (memory allocation) in C++ code

But I can make a utility function like this:

Code:
Function BgfxUtilsGetCaps:BgfxCaps()
    Local bgfxCaps:BgfxCaps = New BgfxCaps()
    bgfxGetCaps( bgfxCaps )
    Return bgfxCaps;
End

    Method OnRender:Int()
        Local bgfxCaps:BgfxCaps = BgfxUtilsGetCaps()
    End
But in this case the New is hidden, and if BgfxUtilsGetCaps is called every frame (like in the cube example), a New is created at every frame. May cause unwanted problem for the garbage collector. But may be useful for BgfxUtilsCreateVertexBuffer and BgfxUtilsCreateIndexBuffer.

Hopefully everyone agrees with this. bgfx.cxs will follow these rules. If you don't understand someting, I can give more examples, so it is clearer.
 

MikeHart

Administrator
Staff member
Joined
Jun 19, 2017
Location
Germany
Looks good to me. Will be a good base to create something more high level, like mojo1.
 

dawlane

Active Member
CX Code Contributor
Joined
Jun 21, 2017
In regard getting/compiling bgfx, my thinking right now is to modify transcc and config file to include git. So git is like mingw or VS2017 it is a tool you have to install. Then transcc can download bgfx from github + tools like genie and compile it. Just an idea.
No need to modify any of the core Cerberus code when you can use the VS project or makefiles to do the work for you. I should point out that not everyone will have git installed on their system, or want it.

a New is created at every frame. May cause unwanted problem for the garbage collector.
I think that will cause problems. If I recall, not all targets call the gc in the same way; and I would suspect that there would be a bit performance hit. Some serious profiling is going to be required to make sure that memory isn't being chewed up and cause a crash, or that frame rate becomes to low or erratic.
 
Last edited:

JaviCervera

Member
3rd Party Module Dev
Joined
Jul 12, 2017
Are you sure bgfx supports Vulkan? Doesn't say so on the project's README.
 

dawlane

Active Member
CX Code Contributor
Joined
Jun 21, 2017
Are you sure bgfx supports Vulkan? Doesn't say so on the project's README.
Doesn't say it in the README, but the header files are in the third-party directory and there is a renderer in there (look for render_vk). And it's one of those projects where you have to look for details from within the source files.
 

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
Looks good to me. Will be a good base to create something more high level, like mojo1.
I think bgfx is more closer to gles20. So I think it is easier to get mojo2. But if you create a global canvas, I think you can easily create a wrapper for mojo1. Just to show an example:

Code:
' mojo1wrapper.cxs may look something like this:

Global _mojo1Canvas

Function DrawCircle : Int ( x:Float, y:Float, r:Float )
    Return _mojo1Canvas.DrawCircle( x, y, r )
End
About Vulkan ...
I think Vulkan is being implemented, look at these two files:
https://github.com/bkaradzic/bgfx/blob/master/src/renderer_vk.cpp
https://github.com/bkaradzic/bgfx/blob/master/src/renderer_vk.h

Sorry I have been quite, been doing the bgfx.cpp and bgfx.cxs file. It was epic. I have finished it and it is compiling, but needs ALOT of testing. Was going to post the code but it was too long. May post it on 2 seperate posts, if possible. I am going to try get mojo2 going with bgfx, may take a while. If it is too hard I might go back and try porting some more examples, to get used to bgfx.

About 64-bit ...
64-bit int will be stored in 2 32-bit Int (eg Field flags:Int[2]). And I have created a function to set the bit:

Code:
Function SetBit:Void( numbers:Int[], bit:Int, value:Int )
    Local index:Int = bit Shr 5
    Local number:Int = numbers[ index ]
    bit &= 31
    numbers[ index ] = number ~ ( (-value ~ number) & (1 Shl bit) )
End
EDIT: I have attached it to this post instead.
 

Attachments

Last edited:

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
Simplifying Mojo 2

1. Remove Mojo 2 shader and use a very simple white shader

I replace the shader code in mojo2.graphics with a simple white shader. White shader is the hello world shader code.

This is the white shader:

Code:
    Const _vertexSource:String = "

        uniform mat4 ModelViewProjectionMatrix;

        attribute vec4 Position;

        void main()
        {
            gl_Position = ModelViewProjectionMatrix * Position;
        }"

    Const _fragmentSource:String = "
        #ifdef GL_ES
            precision mediump float;
        #endif

        void main()
        {
            gl_FragColor=vec4(1.0, 1.0, 1.0, 1.0);
        }"
The vertex shader has 1 uniform the model view projection matrix, and the vertex position. It is possible to remove the model view projection matrix, but the vertex will not be in the correct co-ordinate. The fragment shader puts a white pixel. And here is the code to compile and link those two shaders.

Code:
        Local vshader:=glCompile( GL_VERTEX_SHADER,_vertexSource )
        Local fshader:=glCompile( GL_FRAGMENT_SHADER,_fragmentSource )
       
        Local program:=glCreateProgram()
        glAttachShader program,vshader
        glAttachShader program,fshader
        glDeleteShader vshader
        glDeleteShader fshader
       
        glBindAttribLocation program,0,"position"

        glLink program
At this stage I can still draw circle and simple objects. Mojo 2 uses a mega texture + parser. I need to look into this. But right now it is remove to simplify Mojo 2.

2. Remove all OpenGL code

This is pretty straight forward. I commented out "'Import opengl.gles20" and "'Import glutil". And then, I commented out OpenGL code until it compile AND does not reset.

3. Simplest Mojo 2 code

At this stage I put back the OpenGL code, but just enough so it can draw circle, lines and rectangle.

To initialize the vertex buffer and index buffer:

Code:
    rs_vbo=glCreateBuffer()
    glBindBuffer GL_ARRAY_BUFFER,rs_vbo
    glBufferData GL_ARRAY_BUFFER,PRIM_VBO_SIZE,Null,VBO_USAGE
    glEnableVertexAttribArray 0 ; glVertexAttribPointer 0,2,GL_FLOAT,False,BYTES_PER_VERTEX,0
    glEnableVertexAttribArray 1 ; glVertexAttribPointer 1,2,GL_FLOAT,False,BYTES_PER_VERTEX,8
    glEnableVertexAttribArray 2 ; glVertexAttribPointer 2,2,GL_FLOAT,False,BYTES_PER_VERTEX,16
    glEnableVertexAttribArray 3 ; glVertexAttribPointer 3,4,GL_UNSIGNED_BYTE,True,BYTES_PER_VERTEX,24
   
    rs_ibo=glCreateBuffer()
    glBindBuffer GL_ELEMENT_ARRAY_BUFFER,rs_ibo
    Local idxs:=New DataBuffer( MAX_QUAD_INDICES*4*2,True )
    For Local j:=0 Until 4
        Local k:=j*MAX_QUAD_INDICES*2
        For Local i:=0 Until MAX_QUADS
            idxs.PokeShort i*12+k+0,i*4+j+0
            idxs.PokeShort i*12+k+2,i*4+j+1
            idxs.PokeShort i*12+k+4,i*4+j+2
            idxs.PokeShort i*12+k+6,i*4+j+0
            idxs.PokeShort i*12+k+8,i*4+j+2
            idxs.PokeShort i*12+k+10,i*4+j+3
        Next
    Next
    glBufferData GL_ELEMENT_ARRAY_BUFFER,idxs.Length,idxs,GL_STATIC_DRAW
    idxs.Discard
To compile and link the shaders:

Code:
        Local vshader:=glCompile( GL_VERTEX_SHADER,_vertexSource )
        Local fshader:=glCompile( GL_FRAGMENT_SHADER,_fragmentSource )
       
        Local program:=glCreateProgram()
        glAttachShader program,vshader
        glAttachShader program,fshader
        glDeleteShader vshader
        glDeleteShader fshader
       
        glBindAttribLocation program,0,"position"

        glLink program
To load the model view project matrix into the shader:

Code:
        mvpMatrix=glGetUniformLocation( program,"ModelViewProjectionMatrix" )

...

        glUseProgram program
       
        If mvpMatrix<>-1 glUniformMatrix4fv mvpMatrix,1,False,rs_modelViewProjMatrix
To draw circle, line and rectangle:

Code:
        Select op.order
        Case 1
            glDrawArrays GL_POINTS,index,count
        Case 2
            glDrawArrays GL_LINES,index,count
        Case 3
            glDrawArrays GL_TRIANGLES,index,count
        Case 4
            glDrawElements GL_TRIANGLES,count/4*6,GL_UNSIGNED_SHORT,(index/4*6 + (index&3)*MAX_QUAD_INDICES)*2
        Default
            Local j:=0
            While j<count
                glDrawArrays GL_TRIANGLE_FAN,index+j,op.order
                j+=op.order
            Wend
        End

...

            glBufferSubData GL_ARRAY_BUFFER,0,size,_data,offset
Currently I am working to port these Mojo 2 codes above (initialize, shader and draw) from OpenGL to bgfx.
 

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
Circle, Rectangle, Lines and Points

I have managed to modify Mojo 2 to draw circle, rectangle, lines and points. I have attached a screenshot. The code is messy. I have been learning alot of about bgfx.

mojo2shapes.png

The creating of vertex and index buffer is pretty straight forward. I used bgfxCreateDynamicVertexBuffer and bgfxCreateDynamicIndexBufferMem, because the vertex buffer will be changed. That is how Mojo 2 draws.

I had problem with bgfxMakeRef and used bgfxCopy. But I think I figured it out. When I used bgfxMakeRef, I was passing a DataBuffer, but I called the DataBuffer.Discard later on. That means the memory is free/deleted. If I used bgfxCopy, it allocates memory in bgfx and copy the DataBuffer into that memory, that's why it is working. For bgfxCopy, apparently bgfx will free/delete that memory later on.

The shader codes need to be compiled to a bin file (binary). This is a problem, because Mojo 2 parse the glsl code in text. I can port every Mojo 2 shader codes and create the bin shader files for each targets (DX9, DX11, metal, etc), but that means the bgfx Mojo 2 module does not parse the shader code. On a side note, to translate the shader to glsl or hlsl, it uses C macros. I need to look at this further.

For 64-bit, I am still using :Int[2] array, but I am using this bgfxUtilsSet64Bit function and defining the Const as follows:

Code:
Global BGFX_STATE_PT_TRISTRIP:Int[]          = [ $00010000, $00000000 ]
Global BGFX_STATE_PT_LINES:Int[]             = [ $00020000, $00000000 ]
Global BGFX_STATE_PT_LINESTRIP:Int[]         = [ $00030000, $00000000 ]
Global BGFX_STATE_PT_POINTS:Int[]            = [ $00040000, $00000000 ]

Function bgfxUtilsSet64Bit:Void( numbers:Int[], value:Int[] )
    numbers[0] |= value[0]
    numbers[1] |= value[1]
End

    bgfxUtilsSet64Bit( state, BGFX_STATE_PT_TRISTRIP )
Alot more straight forward then the one I posted above. Should have done that in the first place. But, I am still a little concerned about signed and unsigned Int. I will look into it.

For drawing you have to use bgfxSetState to tell which primitive type you want to use - triangles, triangle strips, line, line strips and points. The default is triangles. So if you don't set a primitive type, then it is drawing triangles.

There is no triangle fan, so I had to use index buffer to simulate a triangle fan.

To control what and how to draw, use bgfxSetDynamicVertexBuffer, and bgfxSetDynamicIndexBuffer. (Note the last two arguments are start index and count, ie where to start drawing and how many.) Call only bgfxSetDynamicVertexBuffer then bgfxSubmit, and it will draw using only vertex buffer. Call both bgfxSetDynamicVertexBuffer and bgfxSetDynamicIndexBuffer then bgfxSubmit, and it will draw using index buffer. bgfxSubmit or bgfxDiscard resets all drawing states, vertex and index buffer. This I had to get used to, because I am used to calling glDrawArrays and glDrawElements.

I am getting there :D Here is a list of unknowns:
1. texture (images in Mojo 2)
2. shaders
3. blending
4. read pixels
5. scissors
6. frame buffers
7. bgfx glfw target
8. signed and unsigned in 64-bit
 
Top Bottom