Batch Optimization for font drawing in 3D APIs

Source: Internet
Author: User

It is disgusting to draw characters in the 3D engine. Drawing one by one is too slow. Make up a large mesh.
Engine-consuming characters. And you still need to lock/unlock VB.
More than one hundred words are drawn. FPS dropped from 600 to more than 80.

After discussion with others. It is more efficient to transmit data such as pos using shader constant.
So we made such a process.
1. Make 72 quad with a size of 1x1. (In fact, you can use one, just drawinstance ).
2. Combine char with the same texture.
3. Prepare a shader with 72 characters (Pos, texture, color ). In fact, up to 81. 81x3 = 243 + 3x4 = 255 (up to 256 constant)
4. Pass these constant at one time. Draw 72 characters at a time.

This advantage is that 1 does not Lock unlock VB. 2. A maximum of 72 characters can be drawn at a time. Higher efficiency.

After this processing, the FPS remains unchanged after 100 characters are drawn.

Begin_namespace_xevol3d;
Class xbatchfontdevice: Public ifontrenderdevice
{
Irenderapi * m_prenderapi;
Efontfilter m_filter;
Iblenderstate * m_blendstate;
Isamplerstate * m_ppointsampler;
Isamplerstate * m_plinearsampler;
Hgpuprogram m_pdeffontshader;
Hgpuprogram m_pusrfontshader;
Idepthstencilstate * m_pstencilstate;

Ivertexstream * m_pvertexstream;
Iinputbuffer * m_pvertexbuffer;
Iinputbuffer * m_pidxbuffer;
Iinputassembler * m_pass;
Int m_nquad;

Float4 m_fontcolor [72];
Float4 m_srcrect [72];
Float4 m_dstrect [72];
Int m_iquadindex;
Ibasetexture * m_ptexture;
Struct xbathfontvertex
{
Xvec4 m_pos;
Xvec2 m_uv [2];
};
Public:
Impl_refcount_object_interface (xbatchfontdevice );
Xbatchfontdevice (irenderapi * prenderapi );
~ Xbatchfontdevice ();
Irenderapi * renderapi () {return m_prenderapi ;}
Public:
Virtual bool resetfontfilter () {return true ;}
Virtual bool setuvlayer (INT nuvlayer );
Virtual bool setshaderprogram (hgpuprogram pprogram );
Virtual bool Init ();
Virtual bool setfontfilter (efontfilter filter );
Virtual bool beginfontrender ();
Virtual bool endfontrender ();
Virtual bool commit ();
Virtual bool drawrectf (ibasetexture * ptexture, float vdestrect [4], const xcolor_4f & color );
Virtual bool drawrectf (ibasetexture * ptexture, float vdestrect [4], float vsrcrect [4], const xcolor_4f & color );
Virtual ibasetexture * createtexture (int w, int H, epixel_format FMT, bool breadable, eresourceusage usage, int nmipmap = 1, int narraysize = 1 );
Virtual bool istexturesupport (epixel_format FMT, bool lockable = true );
};

Bool xbatchfontdevice: setuvlayer (INT nuvlayer)
{

Return true;
}

Bool xbatchfontdevice: setshaderprogram (hgpuprogram pprogram)
{
M_pusrfontshader = pprogram;
Return true;
}

Bool xbatchfontdevice: Init ()
{
Xinputlayoutdesc inputdesc;
Inputdesc. addelement (shader_semantic_position, shadervartype_float4 );
Inputdesc. addelement (shader_semantic_texcoord, shadervartype_float2, 0 );
Inputdesc. addelement (shader_semantic_texcoord, shadervartype_float2, 1 );
Inputdesc. addbufferdesc (resource_usage_default, resource_access_none );

M_pass = m_prenderapi-> createinputassembler (L "batchfont", inputdesc );
M_pvertexstream = m_pass-> createvertexstream ();

M_nquad = m_prenderapi-> intcapsvalue (L "fontbatchcount", 72 );
If (m_nquad> 72) m_nquad = 72;
Xfaceindex16_u indices [72*2];
For (INT I = 0; I <m_nquad; I ++)
{
Int baseindex = I * 4;
Indices [I * 2]. V1 = 0 + baseindex;
Indices [I * 2]. v2 = 2 + baseindex;
Indices [I * 2]. V3 = 1 + baseindex;

Indices [I * 2 + 1]. V1 = 2 + baseindex;
Indices [I * 2 + 1]. v2 = 0 + baseindex;
Indices [I * 2 + 1]. V3 = 3 + baseindex;
}
Xinputbufferdesc idxbufdesc;
Idxbufdesc. m_usage = resource_usage_default;
Idxbufdesc. m_accessflage = resource_access_none;
Idxbufdesc. m_bindtype = bind_as_index_buffer;
M_pidxbuffer = m_prenderapi-> createinputbuffer (72*6, 2, & idxbufdesc, indices );
//////////////////////////////////////// //////////////////////////////////
Xinputbufferdesc vbufdesc;
Vbufdesc. m_usage = resource_usage_default;
Vbufdesc. m_accessflage = resource_access_none;
Vbufdesc. m_bindtype = bind_as_vertex_buffer;

Xbathfontvertex batchvertex [72*4];
Float _ zvalue = m_prenderapi-> get2dzvalue ();
For (INT I = 0; I <72; I ++)
{
Xbathfontvertex * vertex = batchvertex + I * 4;
Vertex [0]. m_uv [0] = vertex [0]. m_uv [1] = xvec2 (0.0f, 1.0f );
Vertex [1]. m_uv [0] = vertex [1]. m_uv [1] = xvec2 (0.0f, 0.0f );
Vertex [2]. m_uv [0] = vertex [2]. m_uv [1] = xvec2 (1.0f, 0.0f );
Vertex [3]. m_uv [0] = vertex [3]. m_uv [1] = xvec2 (1.0f, 1.0f );

Vertex [0]. m_pos = xvec4 (0.0f, 1.0f, _ zvalue, I );
Vertex [1]. m_pos = xvec4 (0.0f, 0.0f, _ zvalue, I );
Vertex [2]. m_pos = xvec4 (1.0f, 0.0f, _ zvalue, I );
Vertex [3]. m_pos = xvec4 (1.0f, 1.0f, _ zvalue, I );
}

M_pvertexstream-> createinputbuffer (0, 4 * m_nquad, & batchvertex, & vbufdesc );
M_pvertexbuffer = m_pvertexstream-> getinputbuffer (0 );
M_pvertexbuffer-> Update (elock_writediscard, batchvertex, sizeof (xbathfontvertex) * 4*72 );

M_iquadindex = 0;

M_filter = efontfilter_point;

If (m_pdeffontshader.ishandle () = false)
{
Hgpuprogram = m_prenderapi-> gpuprogrammanager ()-> load (L "batchfont. vertex", l "font. pixel ");
M_pdeffontshader = hgpuprogram;
}

If (m_pstencilstate = NULL) {m_pstencilstate = m_prenderapi-> createdepthstencilstate (L "overlay ");}
If (m_ppointsampler = NULL) {m_ppointsampler = m_prenderapi-> createsamplerstate (L "fontpoint ");}
If (m_plinearsampler = NULL) {m_plinearsampler = m_prenderapi-> createsamplerstate (L "fontlinear ");}
If (m_blendstate = NULL) {m_blendstate = m_prenderapi-> createblendstate (L "font. Blend ");}
Return true;
}

Bool xbatchfontdevice: setfontfilter (efontfilter filter)
{
M_filter = filter;
If (m_filter = efontfilter_point)
{
Return m_prenderapi-> setsamplerstate (eshader_pixelshader, 0, m_ppointsampler );
}
Else if (m_filter = efontfilter_linear)
{
Return m_prenderapi-> setsamplerstate (eshader_pixelshader, 0, m_plinearsampler );
}
Return false;
}

Xbatchfontdevice: xbatchfontdevice (irenderapi * prenderapi)
{
M_filter = efontfilter_point;
M_pstencilstate = NULL;
M_pdeffontshader.setnull ();
M_prenderapi = prenderapi;
M_ppointsampler = NULL;
M_plinearsampler = NULL;
M_blendstate = NULL;
M_pusrfontshader.setnull ();
M_ptexture = NULL;

M_pvertexstream = NULL;
M_pvertexbuffer = NULL;
M_pidxbuffer = NULL;
M_pass = NULL;
M_nquad = 0;
M_iquadindex = 0;

}

Xbatchfontdevice ::~ Xbatchfontdevice ()
{

}

Bool xbatchfontdevice: beginfontrender ()
{
If (m_pdeffontshader.ishandle () = false)
Return false;
M_prenderapi-> setdepthstencilstate (m_pstencilstate );
M_prenderapi-> setblendstate (m_blendstate );
Igpuprogramparamtable * pshadertable = NULL;
If (m_pusrfontshader)
{
M_prenderapi-> setgpuprogram (m_pusrfontshader); // pushgpuprogram (m_pusrfontshader );
Pshadertable = m_pusrfontshader-> getparamtable (); // pushgpuprogram (m_pusrfontshader );
}
Else
{
M_prenderapi-> setgpuprogram (m_pdeffontshader); // pushgpuprogram (m_pdeffontshader );
Pshadertable = m_pdeffontshader-> getparamtable (); // pushgpuprogram (m_pdeffontshader );
}

Float4x4 matworld;
Float4x4 matproject;
Float4x4 matview;
M_prenderapi-> getcamera ()-> tomatrix (matview, matproject );
M_prenderapi-> getmatrix (matworld. Data, matrixmode_world );

Pshadertable-> setparamater (L "_ matworld", matworld, eshader_vertexshader );
Pshadertable-> setparamater (L "_ matview", matview, eshader_vertexshader );
Pshadertable-> setparamater (L "_ matproject", matproject, eshader_vertexshader );

M_iquadindex = 0;
Return true;
}

Bool xbatchfontdevice: endfontrender ()
{
Commit ();
Return true;
}

Bool xbatchfontdevice: drawrectf (ibasetexture * ptexture, float vdestrect [4], const xcolor_4f & color)
{
If (m_prenderapi)
{
Assert (0 );
Return false;
}
Return false;
}

Bool xbatchfontdevice: Commit ()
{
If (m_iquadindex = 0)
Return true;

Igpuprogramparamtable * pshadertable = NULL;
If (m_pusrfontshader)
{
Pshadertable = m_pusrfontshader-> getparamtable (); // pushgpuprogram (m_pusrfontshader );
}
Else
{
Pshadertable = m_pdeffontshader-> getparamtable (); // pushgpuprogram (m_pdeffontshader );
}

M_prenderapi-> settexturebylayer (0, m_ptexture );
Pshadertable-> setparamater (L "srcrect", m_srcrect, m_iquadindex, 0, eshader_vertexshader );
Pshadertable-> setparamater (L "dstrect", m_dstrect, m_iquadindex, 0, eshader_vertexshader );
Pshadertable-> setparamater (L "rectcolor", m_fontcolor, m_iquadindex, 0, eshader_vertexshader );

M_prenderapi-> setvertexbuffer (m_pvertexbuffer, 0, sizeof (xbathfontvertex ));
M_prenderapi-> setinputassembler (m_pass );
M_prenderapi-> draw (m_pidxbuffer, m_iquadindex * 6 );

M_iquadindex = 0;
Return true;
}

Bool xbatchfontdevice: drawrectf (ibasetexture * ptexture, float vdestrect [4], float vsrcrect [4], const xcolor_4f & color)
{
If (m_prenderapi)
{
If (m_ptexture! = NULL & m_ptexture! = Ptexture)
Commit ();

M_ptexture = ptexture;
Const xtexturedesc & textdesc = ptexture-> DESC ();
Xvec4 & dstrect = * (xvec4 *) vdestrect );
Xvec4 srcrect = * (xvec4 *) vsrcrect );
Const xtexturedesc & DESC = ptexture-> DESC ();

Srcrect. rect. X/= DESC. m_width;
Srcrect. rect. W/= DESC. m_width;

//////////////////////////////////////// //////////////////////////////////
Srcrect. rect. Y/= DESC. m_height;
Srcrect. rect. h/= DESC. m_height;

M_srcrect [m_iquadindex] = srcrect;
M_dstrect [m_iquadindex] = dstrect;
M_fontcolor [m_iquadindex] = float4 (color. R, color. G, color. B, color. );
M_iquadindex ++;
If (m_iquadindex> = m_nquad)
{
Commit ();
}
}
Return false;
}

Ibasetexture * xbatchfontdevice: createtexture (int w, int H, epixel_format FMT, bool breadable, eresourceusage usage, int nmipmap, int narraysize)
{
If (m_prenderapi)
{
Xtextureinitdesc texinitdesc (W, H, FMT );
Texinitdesc. m_breadable = breadable ;//;
Texinitdesc. m_texturedesc.m_nmipmap = nmipmap;
Texinitdesc. m_texturedesc.m_narraysize = narraysize;
Texinitdesc. m_usage = usage;
If (texinitdesc. m_usage = resource_usage_default)
{
Texinitdesc. m_access = 0;
}
Return m_prenderapi-> createtexture (texinitdesc, null, 0 );
}
Return false;
}

Bool xbatchfontdevice: istexturesupport (epixel_format FMT, bool lockable)
{
If (m_prenderapi)
{
Return m_prenderapi-> istexturesupport (FMT, lockable );
}
Return false;
}

End_namespace_xevol3d;

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.