3D API中,字体绘制的Batch优化
发布日期:2021-10-01 11:36:10 浏览次数:1 分类:技术文章

本文共 9311 字,大约阅读时间需要 31 分钟。

在3D引擎中绘制字符是很恶心的事情。一个个绘制吧又太慢。组成一个大mesh吧。

又太耗引擎的人品。而且还是得lock/unlock vb。

才绘制了一百多个字。 fps从600掉到80多。


经过跟别人的讨论。pos之类的数据用shader constant来传递会效率高一些。

于是做了这样个处理。

1. 做72个1x1大小的Quad。 (其实可以用一个,DrawInstance就好了)。

2. 将纹理相同的char集合起来。

3. 准备一个shader接受 72个字符的信息(pos , texture , color)。其实最多可以81个。 81x3 = 243 + 3 x 4 = 255(最多256个constant)

4. 将这些constant一次性传递过去。一次绘制72个字符。


这个好处是1 没有lock unlock vb。2. 一次绘制最多72个字符。效率更高。


这样处理后,绘制100个字符后, fps基本没有多大的变化。


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 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.a);

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;

转载地址:https://blog.csdn.net/iteye_4639/article/details/82472064 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:游戏资源打包
下一篇:游戏引擎多线程

发表评论

最新留言

不错!
[***.144.177.141]2024年04月20日 01时34分12秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章