示例#1
0
 public void Submit()
 {
     Bgfx.SetVertexBuffer(vertexBuffer, count * 4);
     Bgfx.SetIndexBuffer(indexBuffer, 0, count * 6);
     Bgfx.SetRenderState(RenderState.ColorWrite | RenderState.BlendFunction(RenderState.BlendSourceAlpha, RenderState.BlendInverseSourceAlpha));
     Bgfx.Submit(0);
 }
示例#2
0
        private unsafe void ImplDrawSurface(RenderSurface surface, int index)
        {
            var vertex_buffer = new TransientVertexBuffer(4, Vertex2DLayout);

            fixed(void *v = surface.Vertices)
            {
                Unsafe.CopyBlock((void *)vertex_buffer.Data, v, (uint)(4 * Vertex2D.Stride));
            }

            var pass = (byte)(max_render_pass + index + 1);

            gfx.SetViewport(pass, 0, 0, Game.Instance.ScreenSize.W, Game.Instance.ScreenSize.H);

            var proj = screen_projection;

            gfx.SetProjection(pass, &proj.M11);

            //gfx.SetClearColor(pass, Color.Blue);

            Bgfx.SetTexture(0, current_shader_program.Samplers[0], surface.RenderTarget.NativeTexture, TextureFlags.FilterPoint | TextureFlags.ClampUVW);

            Bgfx.SetRenderState(render_state);

            Bgfx.SetIndexBuffer(index_buffer, 0, 6);

            Bgfx.SetVertexBuffer(0, vertex_buffer, 0, vertex_index);

            Bgfx.Submit(pass, surface.Shader?.Program ?? current_shader_program.Program);
        }
示例#3
0
 public void SetIndexBuffer(GpuIndexBuffer buffer, int startIndex = 0, int count = -1)
 {
     if (buffer.Flags.HasFlag(GpuBufferFlags.Dynamic) || buffer.Flags.HasFlag(GpuBufferFlags.ComputeWrite))
     {
         Bgfx.SetIndexBuffer((DynamicIndexBuffer)buffer.GetNativeObject(), startIndex, count);
     }
     else
     {
         Bgfx.SetIndexBuffer((IndexBuffer)buffer.GetNativeObject(), startIndex, count);
     }
 }
示例#4
0
        public void Submit(
            byte view,
            int vertex_count,
            ShaderProgram shader,
            IndexBuffer index_buffer,
            TransientVertexBuffer vertex_buffer,
            Texture2D texture,
            RenderState render_state)
        {
            Bgfx.SetTexture(0, shader.Samplers[0], texture.Texture, texture.TexFlags);

            Bgfx.SetRenderState(render_state);

            Bgfx.SetIndexBuffer(index_buffer, 0, vertex_count / 4 * 6);

            Bgfx.SetVertexBuffer(0, vertex_buffer, 0, vertex_count);

            shader.SubmitValues();

            Bgfx.Submit(view, shader.Program);
        }
示例#5
0
        public unsafe void Submit(byte viewId, Program program, Matrix4x4 *transform, RenderStateGroup renderStateGroup, IUniformGroup uniforms, Texture texture, Uniform textureSampler)
        {
            foreach (var group in groups)
            {
                if (uniforms != null)
                {
                    uniforms.SubmitPerDrawUniforms();
                }

                if (texture != null)
                {
                    Bgfx.SetTexture(0, textureSampler, texture);
                }

                Bgfx.SetTransform((float *)transform);
                Bgfx.SetIndexBuffer(group.IndexBuffer);
                Bgfx.SetVertexBuffer(0, group.VertexBuffer);
                Bgfx.SetRenderState(renderStateGroup.State, (int)renderStateGroup.BlendFactorRgba);
                Bgfx.SetStencil(renderStateGroup.FrontFace, renderStateGroup.BackFace);
                Bgfx.Submit(viewId, program);
            }
        }
示例#6
0
        private unsafe void ImplSubmit()
        {
            var vertex_buffer = new TransientVertexBuffer(vertex_index, Vertex2DLayout);

            fixed(void *v = vertices)
            {
                Unsafe.CopyBlock((void *)vertex_buffer.Data, v, (uint)(vertex_index * Vertex2D.Stride));
            }

            Bgfx.SetTexture(0, current_shader_program.Samplers[0], current_texture.Texture, current_texture.TexFlags);

            Bgfx.SetRenderState(render_state);

            Bgfx.SetIndexBuffer(index_buffer, 0, vertex_index / 4 * 6);

            Bgfx.SetVertexBuffer(0, vertex_buffer, 0, vertex_index);

            current_shader_program.SubmitValues();

            Bgfx.SetViewMode(current_render_pass, ViewMode.Sequential);

            Bgfx.Submit(current_render_pass, current_shader_program.Program);
        }
示例#7
0
 public void SetIndexBuffer(TransientIndexBuffer ib, int startIndex = 0, int count = -1)
 {
     Bgfx.SetIndexBuffer(ib, startIndex, count);
 }
示例#8
0
        /*public void SetVertexBuffer(DynamicVertexBuffer vb, int count = -1)
         * {
         *      Bgfx.SetVertexBuffer(vb.vbHandle, count);
         * }*/

        public void SetIndexBuffer(IndexBuffer ib, int startIndex = 0, int count = -1)
        {
            Bgfx.SetIndexBuffer(ib.handle, startIndex, count);
        }
示例#9
0
    static unsafe void RunCompute(Sample sample, bool indirectSupported)
    {
        // build vertex layouts
        var quadLayout = new VertexLayout();

        quadLayout.Begin()
        .Add(VertexAttributeUsage.Position, 2, VertexAttributeType.Float)
        .End();

        var computeLayout = new VertexLayout();

        computeLayout.Begin()
        .Add(VertexAttributeUsage.TexCoord0, 4, VertexAttributeType.Float)
        .End();

        // static quad data
        var vb = new VertexBuffer(MemoryBlock.FromArray(QuadVertices), quadLayout);
        var ib = new IndexBuffer(MemoryBlock.FromArray(QuadIndices));

        // create compute buffers
        var currPositionBuffer0 = new DynamicVertexBuffer(1 << 15, computeLayout, BufferFlags.ComputeReadWrite);
        var currPositionBuffer1 = new DynamicVertexBuffer(1 << 15, computeLayout, BufferFlags.ComputeReadWrite);
        var prevPositionBuffer0 = new DynamicVertexBuffer(1 << 15, computeLayout, BufferFlags.ComputeReadWrite);
        var prevPositionBuffer1 = new DynamicVertexBuffer(1 << 15, computeLayout, BufferFlags.ComputeReadWrite);

        // load shaders
        var particleProgram        = ResourceLoader.LoadProgram("vs_particle", "fs_particle");
        var initInstancesProgram   = ResourceLoader.LoadProgram("cs_init_instances");
        var updateInstancesProgram = ResourceLoader.LoadProgram("cs_update_instances");

        // indirect rendering support
        var  indirectProgram = SharpBgfx.Program.Invalid;
        var  indirectBuffer  = IndirectBuffer.Invalid;
        bool useIndirect     = false;

        if (indirectSupported)
        {
            indirectProgram = ResourceLoader.LoadProgram("cs_indirect");
            indirectBuffer  = new IndirectBuffer(2);
            useIndirect     = true;
        }

        // setup params uniforms
        var paramData = new ParamsData {
            TimeStep          = 0.0157f,
            DispatchSize      = 32,
            Gravity           = 0.109f,
            Damping           = 0.25f,
            ParticleIntensity = 0.64f,
            ParticleSize      = 0.279f,
            BaseSeed          = 57,
            ParticlePower     = 3.5f,
            InitialSpeed      = 3.2f,
            InitialShape      = 1,
            MaxAccel          = 100.0f
        };

        // have the compute shader run initialization
        var u_params = new Uniform("u_params", UniformType.Vector4, 3);

        Bgfx.SetUniform(u_params, &paramData, 3);
        Bgfx.SetComputeBuffer(0, prevPositionBuffer0, ComputeBufferAccess.Write);
        Bgfx.SetComputeBuffer(1, currPositionBuffer0, ComputeBufferAccess.Write);
        Bgfx.Dispatch(0, initInstancesProgram, MaxParticleCount / ThreadGroupUpdateSize);

        // start the frame clock
        var clock = new Clock();

        clock.Start();

        // main loop
        while (sample.ProcessEvents(ResetFlags.Vsync))
        {
            // tick the clock
            var elapsed = clock.Frame();
            var time    = clock.TotalTime();

            // write some debug text
            Bgfx.DebugTextClear();
            Bgfx.DebugTextWrite(0, 1, DebugColor.White, DebugColor.Blue, "SharpBgfx/Samples/24-NBody");
            Bgfx.DebugTextWrite(0, 2, DebugColor.White, DebugColor.Cyan, "Description: N-body simulation with compute shaders using buffers.");
            Bgfx.DebugTextWrite(0, 3, DebugColor.White, DebugColor.Cyan, "Frame: {0:F3} ms", elapsed * 1000);

            // fill the indirect buffer if we're using it
            if (useIndirect)
            {
                Bgfx.SetUniform(u_params, &paramData, 3);
                Bgfx.SetComputeBuffer(0, indirectBuffer, ComputeBufferAccess.Write);
                Bgfx.Dispatch(0, indirectProgram);
            }

            // update particle positions
            Bgfx.SetComputeBuffer(0, prevPositionBuffer0, ComputeBufferAccess.Read);
            Bgfx.SetComputeBuffer(1, currPositionBuffer0, ComputeBufferAccess.Read);
            Bgfx.SetComputeBuffer(2, prevPositionBuffer1, ComputeBufferAccess.Write);
            Bgfx.SetComputeBuffer(3, currPositionBuffer1, ComputeBufferAccess.Write);
            Bgfx.SetUniform(u_params, &paramData, 3);
            if (useIndirect)
            {
                Bgfx.Dispatch(0, updateInstancesProgram, indirectBuffer, 1);
            }
            else
            {
                Bgfx.Dispatch(0, updateInstancesProgram, paramData.DispatchSize);
            }

            // ping-pong the buffers for next frame
            Swap(ref currPositionBuffer0, ref currPositionBuffer1);
            Swap(ref prevPositionBuffer0, ref prevPositionBuffer1);

            // view transforms for particle rendering
            var viewMatrix = Matrix4x4.CreateLookAt(new Vector3(0.0f, 0.0f, -45.0f), -Vector3.UnitZ, Vector3.UnitY);
            var projMatrix = Matrix4x4.CreatePerspectiveFieldOfView((float)Math.PI / 4, (float)sample.WindowWidth / sample.WindowHeight, 0.1f, 10000.0f);
            Bgfx.SetViewTransform(0, &viewMatrix.M11, &projMatrix.M11);
            Bgfx.SetViewRect(0, 0, 0, sample.WindowWidth, sample.WindowHeight);

            // draw the particles
            Bgfx.SetVertexBuffer(vb);
            Bgfx.SetIndexBuffer(ib);
            Bgfx.SetInstanceDataBuffer(currPositionBuffer0, 0, paramData.DispatchSize * ThreadGroupUpdateSize);
            Bgfx.SetRenderState(RenderState.ColorWrite | RenderState.BlendAdd | RenderState.DepthTestAlways);
            if (useIndirect)
            {
                Bgfx.Submit(0, particleProgram, indirectBuffer);
            }
            else
            {
                Bgfx.Submit(0, particleProgram);
            }

            // done with frame
            Bgfx.Frame();
        }

        // cleanup
        if (indirectSupported)
        {
            indirectProgram.Dispose();
            indirectBuffer.Dispose();
        }

        u_params.Dispose();
        currPositionBuffer0.Dispose();
        currPositionBuffer1.Dispose();
        prevPositionBuffer0.Dispose();
        prevPositionBuffer1.Dispose();
        updateInstancesProgram.Dispose();
        initInstancesProgram.Dispose();
        particleProgram.Dispose();
        ib.Dispose();
        vb.Dispose();
    }
示例#10
0
    static unsafe void RenderThread(Sample sample)
    {
        // initialize the renderer
        Bgfx.Init();
        Bgfx.Reset(sample.WindowWidth, sample.WindowHeight, ResetFlags.None);

        // enable debug text
        Bgfx.SetDebugFeatures(DebugFeatures.DisplayText);

        // set view 0 clear state
        Bgfx.SetViewClear(0, ClearTargets.Color | ClearTargets.Depth, 0x303030ff);

        // create vertex and index buffers
        var vbh = Cube.CreateVertexBuffer();
        var ibh = Cube.CreateIndexBuffer();

        // load shaders
        var program = ResourceLoader.LoadProgram("vs_cubes", "fs_cubes");

        // start the frame clock
        var clock = new Clock();

        clock.Start();

        int   cubeDim    = 15;
        float lastUpdate = 0.0f;
        int   frameCount = 0;

        // main loop
        while (sample.ProcessEvents(ResetFlags.None))
        {
            // set view 0 viewport
            Bgfx.SetViewRect(0, 0, 0, sample.WindowWidth, sample.WindowHeight);

            // view transforms
            var viewMatrix = Matrix4x4.CreateLookAt(new Vector3(0.0f, 0.0f, -35.0f), Vector3.Zero, Vector3.UnitY);
            var projMatrix = Matrix4x4.CreatePerspectiveFieldOfView((float)Math.PI / 3, (float)sample.WindowWidth / sample.WindowHeight, 0.1f, 100.0f);
            Bgfx.SetViewTransform(0, &viewMatrix.M11, &projMatrix.M11);

            // make sure view 0 is cleared if no other draw calls are submitted
            Bgfx.Touch(0);

            // tick the clock
            var elapsed = clock.Frame();
            var time    = clock.TotalTime();
            if (elapsed > 10)
            {
                elapsed = 0;
            }

            frameCount++;
            lastUpdate += elapsed;
            if (lastUpdate > 1.0f)
            {
                var avgFrameTime = frameCount / lastUpdate;
                if (avgFrameTime > HighThreshold)
                {
                    cubeDim = Math.Min(cubeDim + 2, 40);
                }
                else if (avgFrameTime < LowThreshold)
                {
                    cubeDim = Math.Max(cubeDim - 1, 2);
                }

                frameCount = 0;
                lastUpdate = 0;
            }

            var initial = new Vector3(
                -Step * cubeDim / 2.0f,
                -Step * cubeDim / 2.0f,
                -15.0f
                );

            // write some debug text
            Bgfx.DebugTextClear();
            Bgfx.DebugTextWrite(0, 1, DebugColor.White, DebugColor.Blue, "Description: CPU/driver stress test, maximizing draw calls.");
            Bgfx.DebugTextWrite(0, 2, DebugColor.White, DebugColor.Cyan, "Draw Calls: {0}", cubeDim * cubeDim * cubeDim);
            Bgfx.DebugTextWrite(0, 3, DebugColor.White, DebugColor.Cyan, "Frame:      {0:F3} ms", elapsed * 1000);

            for (int z = 0; z < cubeDim; z++)
            {
                for (int y = 0; y < cubeDim; y++)
                {
                    for (int x = 0; x < cubeDim; x++)
                    {
                        // model matrix
                        var transform = Matrix4x4.CreateFromYawPitchRoll(time + x * 0.21f, time + y * 0.37f, time + y * 0.13f);
                        transform     = Matrix4x4.CreateScale(Scale) * transform;
                        transform.M41 = initial.X + x * Step;
                        transform.M42 = initial.Y + y * Step;
                        transform.M43 = initial.Z + z * Step;
                        Bgfx.SetTransform(&transform.M11);

                        // set pipeline states
                        Bgfx.SetVertexBuffer(0, vbh);
                        Bgfx.SetIndexBuffer(ibh);
                        Bgfx.SetRenderState(RenderState.Default);

                        // submit primitives
                        Bgfx.Submit(0, program);
                    }
                }
            }

            // advance to the next frame. Rendering thread will be kicked to
            // process submitted rendering primitives.
            Bgfx.Frame();
        }

        // clean up
        ibh.Dispose();
        vbh.Dispose();
        program.Dispose();
        Bgfx.Shutdown();
    }
示例#11
0
    static unsafe void RenderThread(Sample sample)
    {
        // initialize the renderer
        Bgfx.Init();
        Bgfx.Reset(sample.WindowWidth, sample.WindowHeight, ResetFlags.Vsync);

        // enable debug text
        Bgfx.SetDebugFeatures(DebugFeatures.DisplayText);

        // set view 0 clear state
        Bgfx.SetViewClear(0, ClearTargets.Color | ClearTargets.Depth, 0x303030ff);

        // create vertex and index buffers
        var vbh = Cube.CreateVertexBuffer();
        var ibh = Cube.CreateIndexBuffer();

        // load shaders
        var program = ResourceLoader.LoadProgram("vs_cubes", "fs_cubes");

        // start the frame clock
        var clock = new Clock();

        clock.Start();

        var imguiController = new ImGuiController(1);

        var image = imguiController.AddTexture(ResourceLoader.LoadTexture("fieldstone-rgba.dds"));

        // main loop
        while (sample.ProcessEvents(ResetFlags.Vsync))
        {
            // set view 0 viewport
            Bgfx.SetViewRect(0, 0, 0, sample.WindowWidth, sample.WindowHeight);

            // view transforms
            var viewMatrix = Matrix4x4.CreateLookAt(new Vector3(0.0f, 0.0f, -35.0f), Vector3.Zero, Vector3.UnitY);
            var projMatrix = Matrix4x4.CreatePerspectiveFieldOfView((float)Math.PI / 3, (float)sample.WindowWidth / sample.WindowHeight, 0.1f, 100.0f);
            Bgfx.SetViewTransform(0, &viewMatrix.M11, &projMatrix.M11);

            // make sure view 0 is cleared if no other draw calls are submitted
            Bgfx.Touch(0);

            // tick the clock
            var elapsed = clock.Frame();
            var time    = clock.TotalTime();

            // write some debug text
            Bgfx.DebugTextClear();
            Bgfx.DebugTextWrite(0, 1, DebugColor.White, DebugColor.Blue, "SharpBgfx/Samples/ImGui");
            Bgfx.DebugTextWrite(0, 2, DebugColor.White, DebugColor.Cyan, "Description: Rendering simple static mesh.");
            Bgfx.DebugTextWrite(0, 3, DebugColor.White, DebugColor.Cyan, "Frame: {0:F3} ms", elapsed * 1000);

            // submit 11x11 cubes
            for (int y = 0; y < 11; y++)
            {
                for (int x = 0; x < 11; x++)
                {
                    // model matrix
                    var transform = Matrix4x4.CreateFromYawPitchRoll(time + x * 0.21f, time + y * 0.37f, 0.0f);
                    transform.M41 = -15.0f + x * 3.0f;
                    transform.M42 = -15.0f + y * 3.0f;
                    transform.M43 = 0.0f;
                    Bgfx.SetTransform(&transform.M11);

                    // set pipeline states
                    Bgfx.SetVertexBuffer(0, vbh);
                    Bgfx.SetIndexBuffer(ibh);
                    Bgfx.SetRenderState(RenderState.Default);

                    // submit primitives
                    Bgfx.Submit(0, program);
                }
            }

            imguiController.StartFrame();

            ImGui.ShowDemoWindow();

            ImGui.SetNextWindowPos(new Vector2(100, 100));
            ImGui.SetNextWindowSize(new Vector2(400, 400));
            ImGui.Begin("Drawing an image");
            ImGui.Image(image, new Vector2(((float)Math.Sin(clock.TotalTime()) + 1) * 200, ((float)Math.Sin(clock.TotalTime()) + 1) * 200));
            ImGui.End();

            imguiController.EndFrame(elapsed, new Vector2(sample.WindowWidth, sample.WindowHeight));


            // advance to the next frame. Rendering thread will be kicked to
            // process submitted rendering primitives.
            Bgfx.Frame();
        }

        // clean up
        ibh.Dispose();
        vbh.Dispose();
        program.Dispose();
        Bgfx.Shutdown();
    }
示例#12
0
    static unsafe void RenderThread(Sample sample)
    {
        // initialize the renderer
        Bgfx.Init(RendererBackend.OpenGL, callbackHandler: new CallbackHandler());
        Bgfx.Reset(sample.WindowWidth, sample.WindowHeight, ResetFlags.MSAA16x | ResetFlags.Capture);

        // enable debug text
        Bgfx.SetDebugFeatures(DebugFeatures.DisplayText);

        // set view 0 clear state
        Bgfx.SetViewClear(0, ClearTargets.Color | ClearTargets.Depth, 0x303030ff);
        Bgfx.SetViewRect(0, 0, 0, sample.WindowWidth, sample.WindowHeight);

        // create vertex and index buffers
        var vbh = Cube.CreateVertexBuffer();
        var ibh = Cube.CreateIndexBuffer();

        // load shaders
        var program = ResourceLoader.LoadProgram("vs_callback", "fs_callback");

        // 5 seconds of 60 Hz video
        var time = 0.0f;

        for (int frame = 0; frame < 300; frame++)
        {
            // write some debug text
            Bgfx.DebugTextClear();
            Bgfx.DebugTextWrite(0, 1, DebugColor.White, DebugColor.Blue, "SharpBgfx/Samples/07-Callback");
            Bgfx.DebugTextWrite(0, 2, DebugColor.White, DebugColor.Cyan, "Description: Implementing application specific callbacks for taking screen shots,");
            Bgfx.DebugTextWrite(13, 3, DebugColor.White, DebugColor.Cyan, "caching OpenGL binary shaders, and video capture.");
            Bgfx.DebugTextWrite(0, 4, DebugColor.White, DebugColor.Cyan, "Frame: {0}", frame);

            // view transforms
            var viewMatrix = Matrix4x4.CreateLookAt(new Vector3(0.0f, 0.0f, 35.0f), Vector3.Zero, Vector3.UnitY);
            var projMatrix = Matrix4x4.CreatePerspectiveFieldOfView((float)Math.PI / 3, (float)sample.WindowWidth / sample.WindowHeight, 0.1f, 100.0f);
            Bgfx.SetViewTransform(0, &viewMatrix.M11, &projMatrix.M11);

            // fixed frame rate
            time += 1.0f / 60.0f;

            // submit 11x11 cubes
            for (int y = 0; y < 11; y++)
            {
                for (int x = 0; x < 11 - y; x++)
                {
                    // model matrix
                    var transform = Matrix4x4.CreateFromYawPitchRoll(time + x * 0.21f, time + y * 0.37f, 0.0f);
                    transform.M41 = -15.0f + x * 3.0f;
                    transform.M42 = -15.0f + y * 3.0f;
                    transform.M43 = 0.0f;
                    Bgfx.SetTransform(&transform.M11);

                    // set pipeline states
                    Bgfx.SetVertexBuffer(0, vbh);
                    Bgfx.SetIndexBuffer(ibh);
                    Bgfx.SetRenderState(RenderState.Default);

                    // submit primitives
                    Bgfx.Submit(0, program);
                }
            }

            // take a screenshot at frame 150
            if (frame == 150)
            {
                Bgfx.RequestScreenShot("frame150");
            }

            // advance to next frame
            Bgfx.Frame();
        }

        // clean up
        ibh.Dispose();
        vbh.Dispose();
        program.Dispose();
        Bgfx.Shutdown();
    }
示例#13
0
    static unsafe void RenderThread(Sample sample)
    {
        // initialize the renderer
        Bgfx.Init();
        Bgfx.Reset(sample.WindowWidth, sample.WindowHeight, ResetFlags.Vsync);

        // enable debug text
        Bgfx.SetDebugFeatures(DebugFeatures.DisplayText);

        // set view 0 clear state
        Bgfx.SetViewClear(0, ClearTargets.Color | ClearTargets.Depth, 0x303030ff);

        // create vertex and index buffers
        var vbh = Cube.CreateVertexBuffer();
        var ibh = Cube.CreateIndexBuffer();

        // load shaders
        var program = ResourceLoader.LoadProgram("vs_instancing", "fs_instancing");

        // start the frame clock
        var clock = new Clock();

        clock.Start();

        // getting caps
        var caps = Bgfx.GetCaps();

        // main loop
        while (sample.ProcessEvents(ResetFlags.Vsync))
        {
            // set view 0 viewport
            Bgfx.SetViewRect(0, 0, 0, sample.WindowWidth, sample.WindowHeight);

            // view transforms
            var viewMatrix = Matrix4x4.CreateLookAt(new Vector3(0.0f, 0.0f, -35.0f), Vector3.Zero, Vector3.UnitY);
            var projMatrix = Matrix4x4.CreatePerspectiveFieldOfView((float)Math.PI / 3, (float)sample.WindowWidth / sample.WindowHeight, 0.1f, 100.0f);
            Bgfx.SetViewTransform(0, &viewMatrix.M11, &projMatrix.M11);

            // make sure view 0 is cleared if no other draw calls are submitted
            Bgfx.Touch(0);

            // tick the clock
            var elapsed = clock.Frame();
            var time    = clock.TotalTime();

            // write some debug text
            Bgfx.DebugTextClear();
            Bgfx.DebugTextWrite(0, 1, DebugColor.White, DebugColor.Blue, "SharpBgfx/Samples/05-Instancing");
            Bgfx.DebugTextWrite(0, 2, DebugColor.White, DebugColor.Cyan, "Description: Geometry instancing.");
            Bgfx.DebugTextWrite(0, 3, DebugColor.White, DebugColor.Cyan, "Frame: {0:F3} ms", elapsed * 1000);

            // check caps
            if ((caps.SupportedFeatures & DeviceFeatures.Instancing) != DeviceFeatures.Instancing)
            {
                // instancing not supported
                Bgfx.DebugTextWrite(0, 3, DebugColor.White, DebugColor.Red, "Instancing not supported!");
            }
            else
            {
                const int instanceStride = 80;
                const int instanceCount  = 121;

                var idb = new InstanceDataBuffer(instanceCount, instanceStride);

                // fill in InstanceDataBuffer
                byte *dataPtr = (byte *)idb.Data.ToPointer();
                // TODO: extract idb->data->num
                for (int y = 0; y < 11; y++)
                {
                    for (int x = 0; x < 11; x++)
                    {
                        float *matrix     = (float *)dataPtr;
                        var    realMatrix = Matrix4x4.CreateFromYawPitchRoll(time + x * 0.21f, time + y * 0.37f, 0f);
                        realMatrix.M41 = -15.0f + x * 3.0f;
                        realMatrix.M42 = -15.0f + y * 3.0f;
                        realMatrix.M43 = 0.0f;
                        // TODO: use proper copy function, not a bycicle
                        float *realMatrixPtr = &realMatrix.M11;
                        for (int i = 0; i < 16; i++)
                        {
                            matrix[i] = realMatrixPtr[i];
                        }

                        float *color = (float *)(dataPtr + 64);
                        color[0] = (float)Math.Sin(time + x / 11.0f) * 0.5f + 0.5f;
                        color[1] = (float)Math.Cos(time + y / 11.0f) * 0.5f + 0.5f;
                        color[2] = (float)Math.Sin(time * 3.0f) * 0.5f + 0.5f;
                        color[3] = 1.0f;

                        dataPtr += instanceStride;
                    }
                }

                // set pipeline states
                Bgfx.SetVertexBuffer(0, vbh);
                Bgfx.SetIndexBuffer(ibh);
                Bgfx.SetInstanceDataBuffer(ref idb);
                Bgfx.SetRenderState(RenderState.Default);

                // submit primitives
                Bgfx.Submit(0, program);
            }

            // advance to the next frame. Rendering thread will be kicked to
            // process submitted rendering primitives.
            Bgfx.Frame();
        }

        // clean up
        ibh.Dispose();
        vbh.Dispose();
        program.Dispose();
        Bgfx.Shutdown();
    }