////////////////////////////////////////////////////////////////////// // // Crytek CryENGINE Source code // // File:GlRenderer.cpp // Description: Implementation of the vertex buffer management // // History: // -Jan 31,2001:Created by Vladimir Kajalin // ////////////////////////////////////////////////////////////////////// #include "RenderPCH.h" #include "GL_Renderer.h" void *CVertexBuffer::GetStream(int nStream, int *nOffs) { if (nOffs) *nOffs = 0; return m_VS[nStream].m_VData; } void *CGLRenderer::GetDynVBPtr(int nVerts, int &nOffs, int Pool) { nOffs = 0; switch(Pool) { case 0: default: if (nVerts <= 2048) { SAFE_DELETE_ARRAY(m_TempDynVB); return m_DynVB; } else { m_TempDynVB = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F [nVerts]; return m_TempDynVB; } break; case 1: case 2: assert(0); break; } return NULL; } void CGLRenderer::DrawDynVB(int nOffs, int Pool, int nVerts) { if (!m_DynVBId) { int size = sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)*2048; /*if (SUPPORTS_GL_ARB_vertex_buffer_object) { glGenBuffersARB(1, &m_DynVBId); glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_DynVBId); glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, NULL, GL_DYNAMIC_DRAW_ARB); } else if(IsVarPresent()) { m_DynVBId = (uint)AllocateVarShunk(size, "Font buf"); glGenFencesNV(1, &m_DynVBFence); }*/ } /*if (SUPPORTS_GL_ARB_vertex_buffer_object) { int nVFormat = VERTEX_FORMAT_P3F_COL4UB_TEX2F; int sizeV = m_VertexSize[nVFormat]; if (nVerts + m_nOffsDMesh3D > 2048) { m_nOffsDMesh3D = 0; } glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_DynVBId); glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeV*m_nOffsDMesh3D, sizeV*nVerts, m_DynVB); m_RP.m_PS.m_MeshUpdateBytes += sizeV*nVerts; SBufInfoTable *pOffs = &gBufInfoTable[nVFormat]; //glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, sizeV, BUFFER_OFFSET(0)); glColorPointer(4, GL_UNSIGNED_BYTE, sizeV, BUFFER_OFFSET(pOffs->OffsColor)); glTexCoordPointer(2, GL_FLOAT, sizeV, BUFFER_OFFSET(pOffs->OffsTC)); glDrawArrays(GL_TRIANGLES, m_nOffsDMesh3D, nVerts); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); m_nOffsDMesh3D += nVerts; }*/ /*else if(IsVarPresent()) { int nVFormat = VERTEX_FORMAT_P3F_COL4UB_TEX2F; int sizeV = m_VertexSize[nVFormat]; if (nVerts + m_nOffsDMesh3D > 2048) { if(m_bDynVBFenceSet && !glTestFenceNV(m_DynVBFence)) glFinishFenceNV(m_DynVBFence); m_bDynVBFenceSet = false; m_nOffsDMesh3D = 0; } SBufInfoTable *pOffs = &gBufInfoTable[nVFormat]; //glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); byte *pDst = (byte *)m_DynVBId; memcpy(&pDst[m_nOffsDMesh3D*sizeV], m_DynVB, sizeV*nVerts); glVertexPointer(3, GL_FLOAT, sizeV, (byte *)m_DynVBId); glColorPointer(4, GL_UNSIGNED_BYTE, sizeV, (byte *)m_DynVBId+pOffs->OffsColor); glTexCoordPointer(2, GL_FLOAT, sizeV, (byte *)m_DynVBId+pOffs->OffsTC); glDrawArrays(GL_TRIANGLES, m_nOffsDMesh3D, nVerts); glSetFenceNV(m_DynVBFence, GL_ALL_COMPLETED_NV); m_bDynVBFenceSet = true; glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); m_nOffsDMesh3D += nVerts; } else*/ { struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *pVB = m_DynVB; if (m_TempDynVB) pVB = m_TempDynVB; glBegin(GL_TRIANGLES); int nTris = nVerts/3; for (int k=0; k 2048) { if(m_bDynVBFenceSet && !glTestFenceNV(m_DynVBFence)) glFinishFenceNV(m_DynVBFence); m_bDynVBFenceSet = false; m_nOffsDMesh3D = 0; } SBufInfoTable *pOffs = &gBufInfoTable[nVFormat]; //glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); byte *pDst = (byte *)m_DynVBId; int nOffs = m_nOffsDMesh3D*sizeV; memcpy(&pDst[nOffs], m_DynVB, sizeV*nVerts); glVertexPointer(3, GL_FLOAT, sizeV, (byte *)m_DynVBId+nOffs); glColorPointer(4, GL_UNSIGNED_BYTE, sizeV, (byte *)m_DynVBId+nOffs+pOffs->OffsColor); glTexCoordPointer(2, GL_FLOAT, sizeV, (byte *)m_DynVBId+nOffs+pOffs->OffsTC); glDrawElements(GL_TRIANGLES,nInds,GL_UNSIGNED_SHORT,pInds); glSetFenceNV(m_DynVBFence, GL_ALL_COMPLETED_NV); m_bDynVBFenceSet = true; glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); m_nOffsDMesh3D += nVerts; } else*/ { glBegin(GL_TRIANGLES); int nTris = nInds/3; for (int k=0; k= 0 && Type < VSF_NUM); void *data; if(IsVarPresent()) { data = AllocateVarShunk(size, szSource); // We couldn't allocate video biffer chunk :( Well. try to deallocate LeafBuffer's ones. if (!data) { CLeafBuffer *pLB = CLeafBuffer::m_Root.m_Prev; while (!data) { if (pLB == &CLeafBuffer::m_Root) { GenerateVBLog("LogVBuffers.txt"); iConsole->Exit("Error: Pipeline buffer overflow. Current geometry is too-oo-oo big (%s) (See LogVBuffers.txt for more info)", gRenDev->GetStatusText(eRS_VidBuffer)); } CLeafBuffer *Next = pLB->m_Prev; if (pLB->m_pVertexBuffer != buf) pLB->Unload(); pLB = Next; data = AllocateVarShunk(size, szSource); } } } else if (SUPPORTS_GL_ARB_vertex_buffer_object) { glGenBuffersARB(1, &buf->m_VS[Type].m_VertBuf.m_nID); glBindBufferARB(GL_ARRAY_BUFFER_ARB, buf->m_VS[Type].m_VertBuf.m_nID); glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, NULL, buf->m_VS[Type].m_bDynamic ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB); buf->m_VS[Type].m_VData = (void *)1; //buf->m_VS[Type].m_VData = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); //buf->m_VS[Type].m_bLocked = true; m_CurVertBufferSize += size; return; } else { // System buffer data=new unsigned char [size]; } buf->m_VS[Type].m_VData = data; } void CGLRenderer::CreateIndexBuffer(SVertexStream *dest,const void *src,int indexcount) { ReleaseIndexBuffer(dest); if (indexcount) { if (SUPPORTS_GL_ARB_vertex_buffer_object) { glGenBuffersARB(1, &dest->m_VertBuf.m_nID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dest->m_VertBuf.m_nID); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexcount*sizeof(ushort), NULL, dest->m_bDynamic ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB); } else dest->m_VData = new ushort[indexcount]; dest->m_nItems = indexcount; } if (src && indexcount) UpdateIndexBuffer(dest, src, indexcount, true); } void CGLRenderer::UpdateIndexBuffer(SVertexStream *dest,const void *src,int indexcount, bool bUnLock) { PROFILE_FRAME(Mesh_UpdateIBuffers); if (src && indexcount) { void *dst = NULL; if (dest->m_nItems < indexcount) { if (dest->m_nItems) ReleaseIndexBuffer(dest); CreateIndexBuffer(dest, NULL, indexcount); } int size = indexcount*sizeof(ushort); if (SUPPORTS_GL_ARB_vertex_buffer_object) { glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dest->m_VertBuf.m_nID); dst = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); dest->m_VData = dst; dest->m_bLocked = true; } else dst = dest->m_VData; if (dst) cryMemcpy(dst, src, size); m_RP.m_PS.m_MeshUpdateBytes += size; if (bUnLock) { if (SUPPORTS_GL_ARB_vertex_buffer_object) { glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); dest->m_bLocked = false; } } } } void CGLRenderer::ReleaseIndexBuffer(SVertexStream *dest) { if (SUPPORTS_GL_ARB_vertex_buffer_object) { if (dest->m_VertBuf.m_nID) glDeleteBuffersARB(1, &dest->m_VertBuf.m_nID); } else SAFE_DELETE_ARRAY(dest->m_VData); dest->Reset(); } CVertexBuffer *CGLRenderer::CreateBuffer(int vertexcount,int vertexformat, const char *szSource, bool bDynamic) { PROFILE_FRAME(Mesh_CreateVBuffers); CVertexBuffer * vtemp = new CVertexBuffer; vtemp->m_bDynamic = bDynamic; int size = m_VertexSize[vertexformat]*vertexcount; if(IsVarPresent()) { vtemp->m_VS[VSF_GENERAL].m_VData = AllocateVarShunk(size, szSource); glGenFencesNV(1, &vtemp->m_fence); // We couldn't allocate video biffer chunk :( Well. try to deallocate LeafBuffer's ones. if (!vtemp->m_VS[VSF_GENERAL].m_VData) { CLeafBuffer *pLB = CLeafBuffer::m_Root.m_Prev; while (!vtemp->m_VS[VSF_GENERAL].m_VData) { if (pLB == &CLeafBuffer::m_Root) { GenerateVBLog("LogVBuffers.txt"); iConsole->Exit("Error: Pipeline buffer overflow. Current geometry cannot fit in video memory (%s) (See LogVBuffers.txt for more info)", gRenDev->GetStatusText(eRS_VidBuffer)); } CLeafBuffer *Next = pLB->m_Prev; pLB->Unload(); pLB = Next; vtemp->m_VS[VSF_GENERAL].m_VData = AllocateVarShunk(size, szSource); } } } else if (SUPPORTS_GL_ARB_vertex_buffer_object) { if (size+m_CurVertBufferSize > m_MaxVertBufferSize) { CLeafBuffer *pLB = CLeafBuffer::m_Root.m_Prev; while (size+m_CurVertBufferSize > m_MaxVertBufferSize) { if (pLB == &CLeafBuffer::m_Root) iConsole->Exit("Error: Pipeline buffer overflow. Current geometry is too-oo-oo big (%s)", gRenDev->GetStatusText(eRS_VidBuffer)); CLeafBuffer *Next = pLB->m_Prev; pLB->Unload(); pLB = Next; } } // create the vertex object glGenBuffersARB(1, &vtemp->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glBindBufferARB(GL_ARRAY_BUFFER_ARB, vtemp->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, NULL, bDynamic ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB); vtemp->m_VS[VSF_GENERAL].m_VData = (void *)1; //vtemp->m_VS[VSF_GENERAL].m_VData = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); //vtemp->m_VS[VSF_GENERAL].m_bLocked = true; m_CurVertBufferSize += size; } else { // System buffer vtemp->m_VS[VSF_GENERAL].m_VData = new unsigned char [size]; vtemp->m_fence = 0; } vtemp->m_vertexformat=vertexformat; vtemp->m_NumVerts = vertexcount; return (vtemp); } /////////////////////////////////////////// // Updates the vertex buffer dest with the data from src // NOTE: src may be NULL, in which case the data will not be copied void CGLRenderer::UpdateBuffer(CVertexBuffer *dest,const void *src,int vertexcount, bool bUnlock, int offs, int Type) { void *pVertices; if(IsVarPresent() && dest && !Type && dest->m_fence && CRenderer::CV_r_syncvbuf) { if(dest->m_bFenceSet && !glTestFenceNV(dest->m_fence)) glFinishFenceNV(dest->m_fence); dest->m_bFenceSet = false; } if (!src) { assert (Type >= 0 && Type <= 3); if (SUPPORTS_GL_ARB_vertex_buffer_object) { if (!Type) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->m_VS[VSF_GENERAL].m_VertBuf.m_nID); if (bUnlock) { // video buffer update if (dest->m_VS[VSF_GENERAL].m_bLocked) { dest->m_VS[VSF_GENERAL].m_bLocked = false; glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); } } else { // video buffer update if (!dest->m_VS[VSF_GENERAL].m_bLocked) { PROFILE_FRAME(Mesh_UpdateVBuffersLock); dest->m_VS[VSF_GENERAL].m_bLocked = true; pVertices = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); dest->m_VS[VSF_GENERAL].m_VData = pVertices; } } } else { for (int i=0; im_VS[i].m_VertBuf.m_nID) continue; glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->m_VS[i].m_VertBuf.m_nID); if (bUnlock) { if (dest->m_VS[i].m_bLocked) { dest->m_VS[i].m_bLocked = false; glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); } } else { if (!dest->m_VS[i].m_bLocked) { PROFILE_FRAME(Mesh_UpdateVBuffersLock); dest->m_VS[i].m_bLocked = true; pVertices = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); dest->m_VS[i].m_VData = pVertices; } } } } } return; } { PROFILE_FRAME(Mesh_UpdateVBuffers); // NOTE: some subsystems need to initialize the system buffer without actually intializing its values; // for that purpose, src may sometimes be NULL if(src && vertexcount) { assert(vertexcount<=dest->m_NumVerts); if(vertexcount>dest->m_NumVerts) { iLog->Log("CGLRenderer::UpdateBuffer: vertexcount>dest->m_NumVerts, %s", GetBufferComment(dest)); return; } if (SUPPORTS_GL_ARB_vertex_buffer_object && dest->m_VS[Type].m_VertBuf.m_nID) { uint IdBuf = dest->m_VS[Type].m_VertBuf.m_nID; glBindBufferARB(GL_ARRAY_BUFFER_ARB, IdBuf); /*if (dest->m_VS[Type].m_bLocked) { glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); dest->m_VS[Type].m_bLocked = false; }*/ if (Type == VSF_GENERAL) { glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, m_VertexSize[dest->m_vertexformat]*offs, m_VertexSize[dest->m_vertexformat]*vertexcount, src); m_RP.m_PS.m_MeshUpdateBytes += m_VertexSize[dest->m_vertexformat]*vertexcount; } else if (Type == VSF_TANGENTS) { glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeof(SPipTangents)*offs, sizeof(SPipTangents)*vertexcount, src); m_RP.m_PS.m_MeshUpdateBytes += sizeof(SPipTangents)*vertexcount; } } else { byte *dst = (byte *)dest->m_VS[Type].m_VData; if (dst) { if (Type == VSF_GENERAL) { cryMemcpy(&dst[m_VertexSize[dest->m_vertexformat]*offs],src,m_VertexSize[dest->m_vertexformat]*vertexcount); m_RP.m_PS.m_MeshUpdateBytes += m_VertexSize[dest->m_vertexformat]*vertexcount; } else if (Type == VSF_TANGENTS) { cryMemcpy(&dst[sizeof(SPipTangents)*offs],src,sizeof(SPipTangents)*vertexcount); m_RP.m_PS.m_MeshUpdateBytes += sizeof(SPipTangents)*vertexcount; } } } } } } #include "../Common/NvTriStrip/NVTriStrip.h" /////////////////////////////////////////// void CGLRenderer::DrawBuffer(CVertexBuffer * src, SVertexStream *indicies,int numindices, int offsindex, int prmode,int vert_start,int vert_num, CMatInfo *mi) { PROFILE_FRAME(Draw_IndexMesh); if (!numindices && !mi) return; assert(indicies || mi); ushort *pInds; if (SUPPORTS_GL_ARB_vertex_buffer_object) pInds = NULL; else pInds = (ushort *)indicies->m_VData; pInds += offsindex; #ifdef _DEBUG if (!SUPPORTS_GL_ARB_vertex_buffer_object) { assert(src); if (indicies) { for(int i=0; im_NumVerts); } } } #endif // _DEBUG if(!src || src->m_vertexformat<0 || src->m_vertexformat>=VERTEX_FORMAT_NUMS) { iLog->Log("Error: CGLRenderer::DrawBuffer: VertexBuffer is NULL (!src || src->m_vertexformat<0 || src->m_vertexformat>5)"); return; } assert(numindices>0); SBufInfoTable *pOffs = &gBufInfoTable[src->m_vertexformat]; switch(src->m_vertexformat) { case VERTEX_FORMAT_TRP3F_COL4UB_TEX2F: { struct_VERTEX_FORMAT_TRP3F_COL4UB_TEX2F * pData = (struct_VERTEX_FORMAT_TRP3F_COL4UB_TEX2F*)src->m_VS[VSF_GENERAL].m_VData; glEnableClientState(GL_TEXTURE_COORD_ARRAY); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glEnableClientState(GL_COLOR_ARRAY); if (SUPPORTS_GL_ARB_vertex_buffer_object) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, src->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glVertexPointer(3, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(0)); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glColorPointer(4, GL_UNSIGNED_BYTE, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsColor)); glTexCoordPointer(2, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsTC)); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indicies->m_VertBuf.m_nID); } else { glVertexPointer(3,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->x); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glColorPointer(4,GL_UNSIGNED_BYTE,m_VertexSize[src->m_vertexformat],&pData->color.bcolor[0]); glTexCoordPointer(2,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->st[0]); } } break; case VERTEX_FORMAT_P3F: { if (SUPPORTS_GL_ARB_vertex_buffer_object) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, src->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glVertexPointer(3, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(0)); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indicies->m_VertBuf.m_nID); } else glVertexPointer(3, GL_FLOAT, m_VertexSize[src->m_vertexformat], src->m_VS[VSF_GENERAL].m_VData); glEnableClientState(GL_VERTEX_ARRAY); } break; case VERTEX_FORMAT_P3F_TEX2F: { struct_VERTEX_FORMAT_P3F_TEX2F * pData = (struct_VERTEX_FORMAT_P3F_TEX2F*)src->m_VS[VSF_GENERAL].m_VData; glClientActiveTextureARB(GL_TEXTURE0_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); if (SUPPORTS_GL_ARB_vertex_buffer_object) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, src->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glVertexPointer(3, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(0)); glTexCoordPointer(2, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsTC)); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indicies->m_VertBuf.m_nID); } else { glVertexPointer(3,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->xyz.x); glTexCoordPointer(2,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->st[0]); } } break; case VERTEX_FORMAT_P3F_N_TEX2F: { struct_VERTEX_FORMAT_P3F_N_TEX2F * pData = (struct_VERTEX_FORMAT_P3F_N_TEX2F*)src->m_VS[VSF_GENERAL].m_VData; glClientActiveTextureARB(GL_TEXTURE0_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); if (SUPPORTS_GL_ARB_vertex_buffer_object) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, src->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glVertexPointer(3, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(0)); glNormalPointer(GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsNormal)); glTexCoordPointer(2, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsTC)); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indicies->m_VertBuf.m_nID); } else { glVertexPointer(3,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->xyz.x); glTexCoordPointer(2,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->st[0]); glNormalPointer(GL_FLOAT, m_VertexSize[src->m_vertexformat], &pData->normal.x); } } break; case VERTEX_FORMAT_P3F_COL4UB_TEX2F: { struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pData = (struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F*)src->m_VS[VSF_GENERAL].m_VData; glClientActiveTextureARB(GL_TEXTURE0_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glEnableClientState(GL_COLOR_ARRAY); if (SUPPORTS_GL_ARB_vertex_buffer_object) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, src->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glVertexPointer(3, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(0)); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glColorPointer(4, GL_UNSIGNED_BYTE, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsColor)); glTexCoordPointer(2, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsTC)); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indicies->m_VertBuf.m_nID); } else { glVertexPointer(3,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->xyz.x); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glColorPointer(4,GL_UNSIGNED_BYTE,m_VertexSize[src->m_vertexformat],&pData->color.bcolor[0]); glTexCoordPointer(2,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->st[0]); } } break; case VERTEX_FORMAT_P3F_N_COL4UB_TEX2F: { struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F * pData = (struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F*)src->m_VS[VSF_GENERAL].m_VData; glClientActiveTextureARB(GL_TEXTURE0_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); if (SUPPORTS_GL_ARB_vertex_buffer_object) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, src->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glVertexPointer(3, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(0)); glNormalPointer(GL_FLOAT,m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsNormal)); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glColorPointer(4, GL_UNSIGNED_BYTE, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsColor)); glTexCoordPointer(2, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsTC)); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indicies->m_VertBuf.m_nID); } else { glVertexPointer(3,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->xyz.x); glNormalPointer(GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->normal.x); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glColorPointer(4,GL_UNSIGNED_BYTE,m_VertexSize[src->m_vertexformat],&pData->color.bcolor[0]); glTexCoordPointer(2,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->st[0]); } } break; case VERTEX_FORMAT_P3F_COL4UB: { struct_VERTEX_FORMAT_P3F_COL4UB * pData = (struct_VERTEX_FORMAT_P3F_COL4UB*)src->m_VS[VSF_GENERAL].m_VData; if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glEnableClientState(GL_COLOR_ARRAY); if (SUPPORTS_GL_ARB_vertex_buffer_object) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, src->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glVertexPointer(3, GL_FLOAT, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(0)); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glColorPointer(4, GL_UNSIGNED_BYTE, m_VertexSize[src->m_vertexformat], BUFFER_OFFSET(pOffs->OffsColor)); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indicies->m_VertBuf.m_nID); } else { glVertexPointer(3,GL_FLOAT,m_VertexSize[src->m_vertexformat],&pData->xyz.x); if(!(m_RP.m_FlagsPerFlush & (RBSI_ALPHAGEN | RBSI_RGBGEN))) glColorPointer(4,GL_UNSIGNED_BYTE,m_VertexSize[src->m_vertexformat],&pData->color.bcolor[0]); } } break; default: iLog->Log("Error: CGLRenderer::DrawBuffer: vertex format not supported: %d", src->m_vertexformat); assert(0); break; } // draw switch (prmode) { case R_PRIMV_TRIANGLES: { glDrawElements(GL_TRIANGLES,numindices,GL_UNSIGNED_SHORT,pInds); m_nPolygons+=numindices/3; } break; case R_PRIMV_TRIANGLE_STRIP: { glDrawElements(GL_TRIANGLE_STRIP,numindices,GL_UNSIGNED_SHORT,pInds); m_nPolygons+=numindices-2; } break; case R_PRIMV_MULTI_GROUPS: { if (mi) { int nGroups = mi->m_dwNumSections; SPrimitiveGroup *gr = mi->m_pPrimitiveGroups; if (gr) { for (int i=0; itype) { case PT_STRIP: glDrawElements(GL_TRIANGLE_STRIP, g->numIndices, GL_UNSIGNED_SHORT, &pInds[g->offsIndex]); break; case PT_LIST: glDrawElements(GL_TRIANGLES, g->numIndices, GL_UNSIGNED_SHORT, &pInds[g->offsIndex]); break; case PT_FAN: glDrawElements(GL_TRIANGLE_FAN, g->numIndices, GL_UNSIGNED_SHORT, &pInds[g->offsIndex]); break; } m_nPolygons += g->numTris; } } } } break; } if(!SUPPORTS_GL_ARB_vertex_buffer_object && IsVarPresent() && !src->m_bFenceSet) { glSetFenceNV(src->m_fence, GL_ALL_COMPLETED_NV); src->m_bFenceSet = true; } // disable arrays switch(src->m_vertexformat) { case VERTEX_FORMAT_P3F_TEX2F: glDisableClientState(GL_TEXTURE_COORD_ARRAY); break; case VERTEX_FORMAT_P3F_COL4UB_TEX2F: glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); break; case VERTEX_FORMAT_P3F_N_COL4UB_TEX2F: glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); break; case VERTEX_FORMAT_P3F_N_TEX2F: glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); break; case VERTEX_FORMAT_P3F_COL4UB: glDisableClientState(GL_COLOR_ARRAY); break; } } void CGLRenderer::SetFenceCompleted(CVertexBuffer * buffer) { if(IsVarPresent() && buffer) { // if(!buffer->m_fence_set) { glSetFenceNV(buffer->m_fence, GL_ALL_COMPLETED_NV); buffer->m_bFenceSet = true; } // gRenDev->CheckError("SetFenceCompleted fence"); } } const char * CGLRenderer::GetBufferComment(CVertexBuffer * pVertBuff) { for(int i=0; pVertBuff && im_VS[VSF_GENERAL].m_VData) return m_alloc_info[i].szSource; } return "Buffer is not allocated in video memory"; } /////////////////////////////////////////// void CGLRenderer::ReleaseBuffer(CVertexBuffer *bufptr) { m_nFrameCreateBuf++; if (bufptr) { if(IsVarPresent()) { if (bufptr->m_VS[VSF_GENERAL].m_VData) { if(bufptr->m_bFenceSet && !glTestFenceNV(bufptr->m_fence)) glFinishFenceNV(bufptr->m_fence); bufptr->m_bFenceSet = false; ReleaseVarShunk(bufptr->m_VS[VSF_GENERAL].m_VData); if (bufptr->m_VS[VSF_TANGENTS].m_VData) ReleaseVarShunk(bufptr->m_VS[VSF_TANGENTS].m_VData); if(bufptr->m_fence) glDeleteFencesNV(1, &bufptr->m_fence); bufptr->m_VS[VSF_GENERAL].m_VData = NULL; bufptr->m_VS[VSF_TANGENTS].m_VData = NULL; bufptr->m_fence=0; } } else if (SUPPORTS_GL_ARB_vertex_buffer_object) { if (bufptr->m_VS[VSF_GENERAL].m_VertBuf.m_nID) { glDeleteBuffersARB(1, &bufptr->m_VS[VSF_GENERAL].m_VertBuf.m_nID); bufptr->m_VS[VSF_GENERAL].m_VertBuf.m_nID = 0; m_CurVertBufferSize -= m_VertexSize[bufptr->m_vertexformat] * bufptr->m_NumVerts; } if (bufptr->m_VS[VSF_TANGENTS].m_VertBuf.m_nID) { glDeleteBuffersARB(1, &bufptr->m_VS[VSF_TANGENTS].m_VertBuf.m_nID); bufptr->m_VS[VSF_TANGENTS].m_VertBuf.m_nID = 0; m_CurVertBufferSize -= sizeof(SPipTangents) * bufptr->m_NumVerts; } } else { if (!bufptr->m_fence) { SAFE_DELETE_ARRAY(bufptr->m_VS[VSF_GENERAL].m_VData); SAFE_DELETE_ARRAY(bufptr->m_VS[VSF_TANGENTS].m_VData); } } delete bufptr; } } void CGLRenderer::InitVAR() { float bufSize = CLAMP(CV_gl_pip_buff_size, 4.0f, 64.0f); m_pip_buffer_size = (int)(bufSize*1024.0f*1024.0f); m_MaxVertBufferSize = m_pip_buffer_size; m_CurVertBufferSize = 0; float pip_allow_VAR = CV_gl_pip_allow_var; if(pip_allow_VAR==0) return; if (!SUPPORTS_GL_NV_vertex_array_range) return; while(1) { // if first try fails - try to allocate less memory iLog->Log("Allocating %.2f MB in %s memory ... ", (float)(m_pip_buffer_size/1024/1024), (pip_allow_VAR == 1.f) ? "Video" : "AGP"); m_AGPbuf = (uchar*)wglAllocateMemoryNV(m_pip_buffer_size/*+100*/, 0.0f, // low read frequency 0.0f, // low write frequency (pip_allow_VAR == 1.f) ? 1.0f : 0.5f); // high priority 1.0 = video, 0.5 = agp if(m_AGPbuf) break; // success iLog->Log("wglAllocateMemoryNV error"); m_pip_buffer_size/=2; // if(m_pip_buffer_size<1) break; // error } if(!m_AGPbuf) iLog->Log("Error: CGLRenderer::InitVAR: wglAllocateMemoryNV error"); if(!m_AGPbuf) return; // crash test ((uchar*)m_AGPbuf)[0]=0; ((uchar*)m_AGPbuf)[m_pip_buffer_size-1]=0; iLog->LogPlus("ok"); glVertexArrayRangeNV(m_pip_buffer_size, m_AGPbuf); glEnableClientState (GL_VERTEX_ARRAY_RANGE_NV); // check status glGetIntegerv(GL_VERTEX_ARRAY_RANGE_VALID_NV, &m_var_valid); if(!m_var_valid) iConsole->Exit("Error: CGLRenderer::InitVAR: NV_vertex_array_range has invalid state"); m_alloc_info.Free(); } void CGLRenderer::ShutDownVAR() { if(m_AGPbuf) wglFreeMemoryNV(m_AGPbuf); m_AGPbuf=0; } void * CGLRenderer::AllocateVarShunk(int bytes_count, const char *szSource) { assert(bytes_count); int best_i = -1; int min_size = 10000000; // find best chunk for(int i=0; i= bytes_count) if(m_alloc_info[i].bytes_num < min_size) { best_i = i; min_size = m_alloc_info[i].bytes_num; } if(best_i>=0) { // use best free chunk // iLog->Log("CGLRenderer::InitVAR::AllocateBufferBytes: buffer reused"); m_alloc_info[best_i].busy = true; m_alloc_info[best_i].szSource = szSource; int bytes_free = m_alloc_info[best_i].bytes_num - bytes_count; if(bytes_free>0) { // modify reused shunk m_alloc_info[best_i].bytes_num = bytes_count; // insert another free shunk alloc_info_struct new_shunk; new_shunk.bytes_num = bytes_free; new_shunk.ptr = (uchar*)m_alloc_info[best_i].ptr + m_alloc_info[best_i].bytes_num; new_shunk.busy = false; if(best_i < m_alloc_info.Count()-1) // if not last m_alloc_info.InsertBefore(new_shunk, best_i+1); else m_alloc_info.Add(new_shunk); } return m_alloc_info[best_i].ptr; } void * res_ptr = 0; int piplevel = GetPipWaterLevel(); if(GetPipWaterLevel() + bytes_count + 100 >= m_pip_buffer_size) { return NULL; iConsole->Exit("Error: Pipline buffer overflow.");// Please increase pip_buffer_size value in engine.ini file and restart"); /* ptr = (void *)new unsigned char [bytes_count]; iLog->Log("Error: pip buffer overflow"); iLog->Log(" Please close app and increase pip_buffer_size value in ini file, sorry :)"); glDisableClientState (GL_VERTEX_ARRAY_RANGE_NV);*/ } else { res_ptr = &m_AGPbuf[GetPipWaterLevel()]; } // register new chunk alloc_info_struct ai; ai.ptr = res_ptr; ai.szSource = szSource; ai.bytes_num = bytes_count; ai.busy = true; m_alloc_info.Add(ai); // iLog->LogToFile("New VAR chunk allocated: %d bytes, wl is %d", bytes_count, GetPipWaterLevel()); return res_ptr; } BOOL CGLRenderer::ReleaseVarShunk(void * p) { for(int i=0; iLog("Error: CGLRenderer::ReleaseVarShunk::ReleasePointer: warninig: pointer not found"); return FALSE; } #ifdef WIN64 #pragma warning( push ) //AMD Port #pragma warning( disable : 4311 ) // I think the use of int's below is okay #endif int CGLRenderer::GetPipWaterLevel() { if(m_alloc_info.Count()) return ((int)m_alloc_info.Last().ptr - (int)m_alloc_info[0].ptr) + m_alloc_info.Last().bytes_num; return 0; } #ifdef WIN64 #pragma warning( pop ) //AMD Port #endif /////////////////////////////////////////// void CGLRenderer::DrawTriStrip(CVertexBuffer *src, int vert_num) { switch (src->m_vertexformat) { case VERTEX_FORMAT_P3F: { struct_VERTEX_FORMAT_P3F * p = (struct_VERTEX_FORMAT_P3F*)src->m_VS[VSF_GENERAL].m_VData; glBegin(GL_TRIANGLE_STRIP); for (int k=0;km_VS[VSF_GENERAL].m_VData; glBegin(GL_TRIANGLE_STRIP); for (int k=0;km_VS[VSF_GENERAL].m_VData; glBegin(GL_TRIANGLE_STRIP); for (int k=0;km_VS[VSF_GENERAL].m_VData; glBegin(GL_TRIANGLE_STRIP); for (int k=0;km_VS[VSF_GENERAL].m_VData; glBegin(GL_TRIANGLE_STRIP); for (int k=0;km_VS[VSF_GENERAL].m_VData; glBegin(GL_TRIANGLE_STRIP); for (int k=0;kszSource, pi2->szSource); if (n > 0) return -1; if (n < 0) return 1; return 0; } int LogVCallbackSize( const VOID* arg1, const VOID* arg2 ) { SLogVBuf *pi1 = (SLogVBuf *)arg1; SLogVBuf *pi2 = (SLogVBuf *)arg2; if (pi1->nMemory > pi2->nMemory) return -1; if (pi1->nMemory < pi2->nMemory) return 1; return 0; } void CGLRenderer::GenerateVBLog(const char *szName) { SLogVBuf LV; TArray LVs; for(int i=0; im_nPolygons++; } glEnd(); }