Index: ps/trunk/source/graphics/Canvas2D.cpp =================================================================== --- ps/trunk/source/graphics/Canvas2D.cpp +++ ps/trunk/source/graphics/Canvas2D.cpp @@ -60,7 +60,7 @@ shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, uvs.data()); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 2); + deviceCommandContext->Draw(0, vertices.size() / 2); } } // anonymous namespace @@ -253,7 +253,8 @@ shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, uvs.data()); shader->AssertPointersBound(); - glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, indices.data()); + m->DeviceCommandContext->SetIndexBufferData(indices.data()); + m->DeviceCommandContext->DrawIndexed(0, indices.size(), 0); } void CCanvas2D::DrawRect(const CRect& rect, const CColor& color) Index: ps/trunk/source/graphics/LOSTexture.cpp =================================================================== --- ps/trunk/source/graphics/LOSTexture.cpp +++ ps/trunk/source/graphics/LOSTexture.cpp @@ -184,7 +184,7 @@ shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); g_Renderer.SetViewport(oldVp); Index: ps/trunk/source/graphics/MiniMapTexture.cpp =================================================================== --- ps/trunk/source/graphics/MiniMapTexture.cpp +++ ps/trunk/source/graphics/MiniMapTexture.cpp @@ -68,7 +68,9 @@ return (0xff000000 | b | g << 8 | r << 16); } -void DrawTexture(const CShaderProgramPtr& shader) +void DrawTexture( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader) { const float quadUVs[] = { @@ -95,7 +97,7 @@ shader->VertexPointer(3, GL_FLOAT, 0, quadVertices); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); } struct MinimapUnitVertex @@ -387,7 +389,7 @@ shader->Uniform(str_textureTransform, terrainTransform); if (m_TerrainTexture) - DrawTexture(shader); + DrawTexture(deviceCommandContext, shader); pipelineStateDesc.blendState.enabled = true; pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = @@ -409,7 +411,7 @@ shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, territoryTexture.GetMinimapTextureMatrix()); - DrawTexture(shader); + DrawTexture(deviceCommandContext, shader); pipelineStateDesc.blendState.enabled = false; pipelineStateDesc.blendState.colorWriteMask = @@ -420,7 +422,7 @@ shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, losTexture.GetMinimapTextureMatrix()); - DrawTexture(shader); + DrawTexture(deviceCommandContext, shader); tech->EndPass(); @@ -528,7 +530,7 @@ scissorRect.width = scissorRect.height = FINAL_TEXTURE_SIZE - 2; deviceCommandContext->SetScissors(1, &scissorRect); - u8* indexBase = m_IndexArray.Bind(deviceCommandContext); + m_IndexArray.UploadIfNeeded(deviceCommandContext); u8* base = m_VertexArray.Bind(deviceCommandContext); const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); @@ -536,7 +538,8 @@ shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); shader->AssertPointersBound(); - glDrawElements(GL_TRIANGLES, m_EntitiesDrawn * 6, GL_UNSIGNED_SHORT, indexBase); + deviceCommandContext->SetIndexBuffer(m_IndexArray.GetBuffer()); + deviceCommandContext->DrawIndexed(m_IndexArray.GetOffset(), m_EntitiesDrawn * 6, 0); g_Renderer.GetStats().m_DrawCalls++; CVertexBuffer::Unbind(deviceCommandContext); Index: ps/trunk/source/graphics/ParticleEmitter.cpp =================================================================== --- ps/trunk/source/graphics/ParticleEmitter.cpp +++ ps/trunk/source/graphics/ParticleEmitter.cpp @@ -200,12 +200,10 @@ Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, const CShaderProgramPtr& shader) { - // Some drivers apparently don't like count=0 in glDrawArrays here, - // so skip all drawing in that case if (m_Particles.empty()) return; - u8* indexBase = m_IndexArray.Bind(deviceCommandContext); + m_IndexArray.UploadIfNeeded(deviceCommandContext); u8* base = m_VertexArray.Bind(deviceCommandContext); GLsizei stride = (GLsizei)m_VertexArray.GetStride(); @@ -220,7 +218,9 @@ shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); shader->AssertPointersBound(); - glDrawElements(GL_TRIANGLES, (GLsizei)(m_Particles.size() * 6), GL_UNSIGNED_SHORT, indexBase); + + deviceCommandContext->SetIndexBuffer(m_IndexArray.GetBuffer()); + deviceCommandContext->DrawIndexed(m_IndexArray.GetOffset(), m_Particles.size() * 6, 0); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_Particles += m_Particles.size(); Index: ps/trunk/source/graphics/ShaderProgram.h =================================================================== --- ps/trunk/source/graphics/ShaderProgram.h +++ ps/trunk/source/graphics/ShaderProgram.h @@ -182,7 +182,7 @@ /** * Checks that all the required vertex attributes have been set. - * Call this before calling glDrawArrays/glDrawElements etc to avoid potential crashes. + * Call this before calling Draw/DrawIndexed etc to avoid potential crashes. */ void AssertPointersBound(); Index: ps/trunk/source/graphics/TextRenderer.cpp =================================================================== --- ps/trunk/source/graphics/TextRenderer.cpp +++ ps/trunk/source/graphics/TextRenderer.cpp @@ -263,13 +263,14 @@ size_t idx = 0; - auto flush = [&idx, &vertexes, &indexes, &shader]() -> void { + auto flush = [deviceCommandContext, &idx, &vertexes, &indexes, &shader]() -> void { if (idx == 0) return; shader->VertexPointer(2, GL_SHORT, sizeof(t2f_v2i), &vertexes[0].x); shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, sizeof(t2f_v2i), &vertexes[0].u); - glDrawElements(GL_TRIANGLES, idx * 6, GL_UNSIGNED_SHORT, &indexes[0]); + deviceCommandContext->SetIndexBufferData(indexes.data()); + deviceCommandContext->DrawIndexed(0, idx * 6, 0); idx = 0; }; Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp +++ ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp @@ -95,7 +95,9 @@ } } -void DrawTexture(CShaderProgramPtr shader, float angle, float x, float y, float x2, float y2, float mapScale) +void DrawTexture( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, float angle, float x, float y, float x2, float y2, float mapScale) { // Rotate the texture coordinates (0,0)-(coordMax,coordMax) around their center point (m,m) // Scale square maps to fit in circular minimap area @@ -126,7 +128,7 @@ shader->VertexPointer(3, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); } } // anonymous namespace @@ -422,7 +424,9 @@ pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = Renderer::Backend::BlendOp::ADD; tech->BeginPass(); - g_Renderer.GetDeviceCommandContext()->SetGraphicsPipelineState(pipelineStateDesc); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); shader = tech->GetShader(); shader->BindTexture(str_baseTex, miniMapTexture.GetTexture()); @@ -435,7 +439,7 @@ const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float angle = GetAngle(); - DrawTexture(shader, angle, x, y, x2, y2, m_MapScale); + DrawTexture(deviceCommandContext, shader, angle, x, y, x2, y2, m_MapScale); tech->EndPass(); } Index: ps/trunk/source/renderer/DebugRenderer.cpp =================================================================== --- ps/trunk/source/renderer/DebugRenderer.cpp +++ ps/trunk/source/renderer/DebugRenderer.cpp @@ -86,7 +86,10 @@ CShaderTechniquePtr debugLineTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); debugLineTech->BeginPass(); - SetGraphicsPipelineStateFromTechAndColor(g_Renderer.GetDeviceCommandContext(), debugLineTech, color, depthTestEnabled); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + SetGraphicsPipelineStateFromTechAndColor( + deviceCommandContext, debugLineTech, color, depthTestEnabled); const CCamera& viewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); @@ -125,7 +128,7 @@ debugLineShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); debugLineShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); + deviceCommandContext->Draw(0, vertices.size() / 3); debugLineTech->EndPass(); #endif @@ -140,7 +143,10 @@ CShaderTechniquePtr debugCircleTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); debugCircleTech->BeginPass(); - SetGraphicsPipelineStateFromTechAndColor(g_Renderer.GetDeviceCommandContext(), debugCircleTech, color); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + SetGraphicsPipelineStateFromTechAndColor( + deviceCommandContext, debugCircleTech, color); const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); @@ -173,7 +179,7 @@ debugCircleShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); debugCircleShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size() / 3); + deviceCommandContext->Draw(0, vertices.size() / 3); debugCircleTech->EndPass(); #endif @@ -199,7 +205,10 @@ CShaderTechniquePtr overlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); overlayTech->BeginPass(); - SetGraphicsPipelineStateFromTechAndColor(g_Renderer.GetDeviceCommandContext(), overlayTech, color, true, wireframe); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + SetGraphicsPipelineStateFromTechAndColor( + deviceCommandContext, overlayTech, color, true, wireframe); CShaderProgramPtr overlayShader = overlayTech->GetShader(); overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); @@ -246,7 +255,7 @@ overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); overlayShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); + deviceCommandContext->Draw(0, vertices.size() / 3); vertices.clear(); @@ -264,7 +273,7 @@ overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); overlayShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); + deviceCommandContext->Draw(0, vertices.size() / 3); #undef ADD overlayTech->EndPass(); @@ -286,8 +295,10 @@ { CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); shaderTech->BeginPass(); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); SetGraphicsPipelineStateFromTechAndColor( - g_Renderer.GetDeviceCommandContext(), shaderTech, color, true, wireframe); + deviceCommandContext, shaderTech, color, true, wireframe); const CShaderProgramPtr& shader = shaderTech->GetShader(); shader->Uniform(str_color, color); @@ -317,7 +328,7 @@ shader->VertexPointer(3, GL_FLOAT, 3 * sizeof(float), data.data()); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6*6); + deviceCommandContext->Draw(0, 6*6); shaderTech->EndPass(); } @@ -326,8 +337,10 @@ { CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); shaderTech->BeginPass(); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); SetGraphicsPipelineStateFromTechAndColor( - g_Renderer.GetDeviceCommandContext(), shaderTech, color, true, wireframe); + deviceCommandContext, shaderTech, color, true, wireframe); const CShaderProgramPtr& shader = shaderTech->GetShader(); shader->Uniform(str_color, color); @@ -361,7 +374,7 @@ shader->VertexPointer(3, GL_FLOAT, 3 * sizeof(float), data.data()); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, data.size() / 5); + deviceCommandContext->Draw(0, data.size() / 5); shaderTech->EndPass(); } Index: ps/trunk/source/renderer/DecalRData.cpp =================================================================== --- ps/trunk/source/renderer/DecalRData.cpp +++ ps/trunk/source/renderer/DecalRData.cpp @@ -211,11 +211,11 @@ if (lastIB != batch.indices->m_Owner) { lastIB = batch.indices->m_Owner; - batch.indices->m_Owner->Bind(deviceCommandContext); + batch.indices->m_Owner->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(batch.indices->m_Owner->GetBuffer()); } - u8* indexBase = nullptr; - glDrawElements(GL_TRIANGLES, batch.indices->m_Count, GL_UNSIGNED_SHORT, indexBase + sizeof(u16) * (batch.indices->m_Index)); + deviceCommandContext->DrawIndexed(batch.indices->m_Index, batch.indices->m_Count, 0); // bump stats g_Renderer.m_Stats.m_DrawCalls++; Index: ps/trunk/source/renderer/HWLightingModelRenderer.cpp =================================================================== --- ps/trunk/source/renderer/HWLightingModelRenderer.cpp +++ ps/trunk/source/renderer/HWLightingModelRenderer.cpp @@ -221,7 +221,8 @@ u8* base = shadermodel->m_Array.Bind(deviceCommandContext); GLsizei stride = (GLsizei)shadermodel->m_Array.GetStride(); - u8* indexBase = m->shadermodeldef->m_IndexArray.Bind(deviceCommandContext); + m->shadermodeldef->m_IndexArray.UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(m->shadermodeldef->m_IndexArray.GetBuffer()); if (streamflags & STREAM_POS) shader->VertexPointer(3, GL_FLOAT, stride, base + shadermodel->m_Position.offset); @@ -231,19 +232,14 @@ shader->AssertPointersBound(); - // render the lot - size_t numFaces = mdldef->GetNumFaces(); + // Render the lot. + const size_t numberOfFaces = mdldef->GetNumFaces(); - // Draw with DrawRangeElements where available, since it might be more efficient -#if CONFIG2_GLES - glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase); -#else - glDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1, - (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase); -#endif + deviceCommandContext->DrawIndexedInRange( + m->shadermodeldef->m_IndexArray.GetOffset(), numberOfFaces * 3, 0, mdldef->GetNumVertices() - 1); - // bump stats + // Bump stats. g_Renderer.m_Stats.m_DrawCalls++; - g_Renderer.m_Stats.m_ModelTris += numFaces; + g_Renderer.m_Stats.m_ModelTris += numberOfFaces; } Index: ps/trunk/source/renderer/InstancingModelRenderer.cpp =================================================================== --- ps/trunk/source/renderer/InstancingModelRenderer.cpp +++ ps/trunk/source/renderer/InstancingModelRenderer.cpp @@ -327,7 +327,8 @@ u8* base = m->imodeldef->m_Array.Bind(deviceCommandContext); GLsizei stride = (GLsizei)m->imodeldef->m_Array.GetStride(); - m->imodeldefIndexBase = m->imodeldef->m_IndexArray.Bind(deviceCommandContext); + m->imodeldef->m_IndexArray.UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(m->imodeldef->m_IndexArray.GetBuffer()); if (streamflags & STREAM_POS) shader->VertexPointer(3, GL_FLOAT, stride, base + m->imodeldef->m_Position.offset); @@ -361,7 +362,7 @@ // Render one model void InstancingModelRenderer::RenderModel( - Renderer::Backend::GL::CDeviceCommandContext* UNUSED(deviceCommandContext), + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, const CShaderProgramPtr& shader, int UNUSED(streamflags), CModel* model, CModelRData* UNUSED(data)) { const CModelDefPtr& mdldef = model->GetModelDef(); @@ -377,19 +378,14 @@ shader->Uniform(str_skinBlendMatrices, mdldef->GetNumBones() + 1, model->GetAnimatedBoneMatrices()); } - // render the lot - size_t numFaces = mdldef->GetNumFaces(); + // Render the lot. + const size_t numberOfFaces = mdldef->GetNumFaces(); - // Draw with DrawRangeElements where available, since it might be more efficient -#if CONFIG2_GLES - glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase); -#else - glDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)m->imodeldef->m_Array.GetNumberOfVertices()-1, - (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase); -#endif + deviceCommandContext->DrawIndexedInRange( + m->imodeldef->m_IndexArray.GetOffset(), numberOfFaces * 3, 0, m->imodeldef->m_Array.GetNumberOfVertices() - 1); - // bump stats + // Bump stats. g_Renderer.m_Stats.m_DrawCalls++; - g_Renderer.m_Stats.m_ModelTris += numFaces; + g_Renderer.m_Stats.m_ModelTris += numberOfFaces; } Index: ps/trunk/source/renderer/OverlayRenderer.cpp =================================================================== --- ps/trunk/source/renderer/OverlayRenderer.cpp +++ ps/trunk/source/renderer/OverlayRenderer.cpp @@ -548,11 +548,12 @@ shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); // Base offsets (in bytes) of the two backing stores relative to their owner VBO - u8* indexBase = m->quadIndices.Bind(deviceCommandContext); + m->quadIndices.UploadIfNeeded(deviceCommandContext); u8* vertexBase = m->quadVertices.Bind(deviceCommandContext); - GLsizei indexStride = m->quadIndices.GetStride(); GLsizei vertexStride = m->quadVertices.GetStride(); + deviceCommandContext->SetIndexBuffer(m->quadIndices.GetBuffer()); + for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it) { QuadBatchData& batchRenderData = it->second; @@ -584,7 +585,7 @@ shader->ColorPointer(m->quadAttributeColor.elems, m->quadAttributeColor.type, vertexStride, vertexBase + m->quadAttributeColor.offset); shader->AssertPointersBound(); - glDrawElements(GL_TRIANGLES, (GLsizei)(batchNumQuads * 6), GL_UNSIGNED_SHORT, indexBase + indexStride * batchRenderData.m_IndicesBase); + deviceCommandContext->DrawIndexed(m->quadIndices.GetOffset() + batchRenderData.m_IndicesBase, batchNumQuads * 6, 0); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris += batchNumQuads*2; @@ -668,7 +669,7 @@ shader->VertexPointer(3, GL_FLOAT, sizeof(CVector3D), &position[0].X); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris += 2; @@ -788,7 +789,8 @@ shader->Uniform(str_color, sphere->m_Color); - glDrawElements(GL_TRIANGLES, m->sphereIndexes.size(), GL_UNSIGNED_SHORT, &m->sphereIndexes[0]); + deviceCommandContext->SetIndexBufferData(m->sphereIndexes.data()); + deviceCommandContext->DrawIndexed(0, m->sphereIndexes.size(), 0); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris = m->sphereIndexes.size()/3; Index: ps/trunk/source/renderer/PatchRData.cpp =================================================================== --- ps/trunk/source/renderer/PatchRData.cpp +++ ps/trunk/source/renderer/PatchRData.cpp @@ -669,8 +669,6 @@ } } -// Types used for glMultiDrawElements batching: - // To minimise the cost of memory allocations, everything used for computing // batches uses a arena allocator. (All allocations are short-lived so we can // just throw away the whole arena at the end of each frame.) @@ -702,7 +700,7 @@ } // Each multidraw batch has a list of index counts, and a list of pointers-to-first-indexes -using BatchElements = std::pair>, std::vector>>; +using BatchElements = std::pair>, std::vector>>; // Group batches by index buffer using IndexBufferBatches = PooledBatchMap; @@ -760,8 +758,7 @@ batch.first.push_back(splat.m_IndexCount); - u8* indexBase = nullptr; - batch.second.push_back(indexBase + sizeof(u16)*(patch->m_VBBaseIndices->m_Index + splat.m_IndexStart)); + batch.second.push_back(patch->m_VBBaseIndices->m_Index + splat.m_IndexStart); } } @@ -814,15 +811,13 @@ for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) { - it->first->Bind(deviceCommandContext); + it->first->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(it->first->GetBuffer()); BatchElements& batch = it->second; - // Don't use glMultiDrawElements here since it doesn't have a significant - // performance impact and it suffers from various driver bugs (e.g. it breaks - // in Mesa 7.10 swrast with index VBOs) for (size_t i = 0; i < batch.first.size(); ++i) - glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); + deviceCommandContext->DrawIndexed(batch.second[i], batch.first[i], 0); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; @@ -928,8 +923,7 @@ BatchElements& batch = PooledPairGet(PooledMapGet(batches.back().m_Batches, vertices->m_Owner, arena), indices->m_Owner, arena); batch.first.push_back(splats.back().m_IndexCount); - u8* indexBase = nullptr; - batch.second.push_back(indexBase + sizeof(u16)*(indices->m_Index + splats.back().m_IndexStart)); + batch.second.push_back(indices->m_Index + splats.back().m_IndexStart); splats.pop_back(); } @@ -1045,12 +1039,13 @@ for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) { - it->first->Bind(deviceCommandContext); + it->first->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(it->first->GetBuffer()); BatchElements& batch = it->second; for (size_t i = 0; i < batch.first.size(); ++i) - glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); + deviceCommandContext->DrawIndexed(batch.second[i], batch.first[i], 0); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_BlendSplats++; @@ -1072,13 +1067,13 @@ PROFILE3("render terrain streams"); // Each batch has a list of index counts, and a list of pointers-to-first-indexes - using StreamBatchElements = std::pair, std::vector > ; + using StreamBatchElements = std::pair, std::vector>; // Group batches by index buffer - using StreamIndexBufferBatches = std::map ; + using StreamIndexBufferBatches = std::map; // Group batches by vertex buffer - using StreamVertexBufferBatches = std::map ; + using StreamVertexBufferBatches = std::map; StreamVertexBufferBatches batches; @@ -1091,8 +1086,7 @@ batch.first.push_back(patch->m_VBBaseIndices->m_Count); - u8* indexBase = nullptr; - batch.second.push_back(indexBase + sizeof(u16)*(patch->m_VBBaseIndices->m_Index)); + batch.second.push_back(patch->m_VBBaseIndices->m_Index); } PROFILE_END("compute batches"); @@ -1115,12 +1109,13 @@ for (const std::pair& batchIndexBuffer : streamBatch.second) { - batchIndexBuffer.first->Bind(deviceCommandContext); + batchIndexBuffer.first->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(batchIndexBuffer.first->GetBuffer()); const StreamBatchElements& batch = batchIndexBuffer.second; for (size_t i = 0; i < batch.first.size(); ++i) - glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); + deviceCommandContext->DrawIndexed(batch.second[i], batch.first[i], 0); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; @@ -1187,7 +1182,7 @@ shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, patch->m_VBSides->m_Index, (GLsizei)patch->m_VBSides->m_Count); + deviceCommandContext->Draw(patch->m_VBSides->m_Index, (GLsizei)patch->m_VBSides->m_Count); // bump stats g_Renderer.m_Stats.m_DrawCalls++; @@ -1433,6 +1428,8 @@ if (!m_VBWater) return; + m_VBWaterIndices->m_Owner->UploadIfNeeded(deviceCommandContext); + SWaterVertex* base = reinterpret_cast(m_VBWater->m_Owner->Bind(deviceCommandContext)); // Setup data pointers. @@ -1443,10 +1440,8 @@ shader->AssertPointersBound(); - u8* indexBase = m_VBWaterIndices->m_Owner->Bind(deviceCommandContext); - glDrawElements( - GL_TRIANGLES, static_cast(m_VBWaterIndices->m_Count), - GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndices->m_Index)); + deviceCommandContext->SetIndexBuffer(m_VBWaterIndices->m_Owner->GetBuffer()); + deviceCommandContext->DrawIndexed(m_VBWaterIndices->m_Index, m_VBWaterIndices->m_Count, 0); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndices->m_Count / 3; @@ -1463,6 +1458,8 @@ if (!m_VBWaterShore) return; + m_VBWaterIndicesShore->m_Owner->UploadIfNeeded(deviceCommandContext); + SWaterVertex* base = reinterpret_cast(m_VBWaterShore->m_Owner->Bind(deviceCommandContext)); const GLsizei stride = sizeof(SWaterVertex); @@ -1471,9 +1468,8 @@ shader->AssertPointersBound(); - u8* indexBase = m_VBWaterIndicesShore->m_Owner->Bind(deviceCommandContext); - glDrawElements(GL_TRIANGLES, static_cast(m_VBWaterIndicesShore->m_Count), - GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndicesShore->m_Index)); + deviceCommandContext->SetIndexBuffer(m_VBWaterIndicesShore->m_Owner->GetBuffer()); + deviceCommandContext->DrawIndexed(m_VBWaterIndicesShore->m_Index, m_VBWaterIndicesShore->m_Count, 0); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndicesShore->m_Count / 3; Index: ps/trunk/source/renderer/PostprocManager.cpp =================================================================== --- ps/trunk/source/renderer/PostprocManager.cpp +++ ps/trunk/source/renderer/PostprocManager.cpp @@ -231,7 +231,7 @@ shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); g_Renderer.SetViewport(oldVp); @@ -287,7 +287,7 @@ shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); g_Renderer.SetViewport(oldVp); @@ -312,7 +312,7 @@ shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); g_Renderer.SetViewport(oldVp); @@ -432,7 +432,7 @@ shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); shaderTech->EndPass(pass); Index: ps/trunk/source/renderer/ShadowMap.cpp =================================================================== --- ps/trunk/source/renderer/ShadowMap.cpp +++ ps/trunk/source/renderer/ShadowMap.cpp @@ -750,7 +750,7 @@ texShader->VertexPointer(2, GL_FLOAT, 0, boxVerts); texShader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, boxUV); texShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); texTech->EndPass(); Index: ps/trunk/source/renderer/SilhouetteRenderer.cpp =================================================================== --- ps/trunk/source/renderer/SilhouetteRenderer.cpp +++ ps/trunk/source/renderer/SilhouetteRenderer.cpp @@ -494,7 +494,7 @@ r.x0, r.y1, }; shader->VertexPointer(2, GL_SHORT, 0, verts); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); } shaderTech->EndPass(); Index: ps/trunk/source/renderer/SkyManager.cpp =================================================================== --- ps/trunk/source/renderer/SkyManager.cpp +++ ps/trunk/source/renderer/SkyManager.cpp @@ -248,7 +248,7 @@ GL_TEXTURE0, 3, GL_FLOAT, stride, base + m_AttributeUV.offset); shader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, m_VertexArray.GetNumberOfVertices()); + deviceCommandContext->Draw(0, m_VertexArray.GetNumberOfVertices()); skytech->EndPass(); #endif Index: ps/trunk/source/renderer/TerrainOverlay.cpp =================================================================== --- ps/trunk/source/renderer/TerrainOverlay.cpp +++ ps/trunk/source/renderer/TerrainOverlay.cpp @@ -232,7 +232,7 @@ overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); overlayShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); + deviceCommandContext->Draw(0, vertices.size() / 3); overlayTech->EndPass(); #endif @@ -300,7 +300,7 @@ overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); overlayShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); + deviceCommandContext->Draw(0, vertices.size() / 3); overlayTech->EndPass(); #endif Index: ps/trunk/source/renderer/TerrainRenderer.cpp =================================================================== --- ps/trunk/source/renderer/TerrainRenderer.cpp +++ ps/trunk/source/renderer/TerrainRenderer.cpp @@ -212,7 +212,7 @@ debugOverlayShader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, waterPos); debugOverlayShader->AssertPointersBound(); - glDrawArrays(GL_TRIANGLES, 0, 6); + deviceCommandContext->Draw(0, 6); } debugOverlayTech->EndPass(); Index: ps/trunk/source/renderer/TexturedLineRData.cpp =================================================================== --- ps/trunk/source/renderer/TexturedLineRData.cpp +++ ps/trunk/source/renderer/TexturedLineRData.cpp @@ -48,6 +48,9 @@ line.m_TextureBase->UploadBackendTextureIfNeeded(deviceCommandContext); line.m_TextureMask->UploadBackendTextureIfNeeded(deviceCommandContext); + + m_VBIndices->m_Owner->UploadIfNeeded(deviceCommandContext); + shader->BindTexture(str_baseTex, line.m_TextureBase->GetBackendTexture()); shader->BindTexture(str_maskTex, line.m_TextureMask->GetBackendTexture()); shader->Uniform(str_objectColor, line.m_Color); @@ -65,10 +68,10 @@ if (streamFlags & STREAM_UV1) shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &vertexBase->m_UVs[0]); - u8* indexBase = m_VBIndices->m_Owner->Bind(deviceCommandContext); - shader->AssertPointersBound(); - glDrawElements(GL_TRIANGLES, m_VBIndices->m_Count, GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*m_VBIndices->m_Index); + + deviceCommandContext->SetIndexBuffer(m_VBIndices->m_Owner->GetBuffer()); + deviceCommandContext->DrawIndexed(m_VBIndices->m_Index, m_VBIndices->m_Count, 0); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris += m_VBIndices->m_Count/3; Index: ps/trunk/source/renderer/VertexArray.h =================================================================== --- ps/trunk/source/renderer/VertexArray.h +++ ps/trunk/source/renderer/VertexArray.h @@ -179,17 +179,22 @@ // All vertex data is lost when a vertex array is re-layouted. void Layout(); // (Re-)Upload the attributes of the vertex array from the backing store to - // the underlying VBO object. + // the underlying buffer. void Upload(); // Make this vertex array's data available for the next series of calls to Bind void PrepareForRendering(); // Bind this array, returns the base address for calls to glVertexPointer etc. u8* Bind(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); + void UploadIfNeeded(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); // If you know for certain that you'll never have to change the data again, // call this to free some memory. void FreeBackingStore(); + Renderer::Backend::GL::CBuffer* GetBuffer() { return m_VB ? m_VB->m_Owner->GetBuffer() : nullptr; } + + uint32_t GetOffset() const { return m_VB ? m_VB->m_Index : 0; } + private: void Free(); @@ -212,9 +217,7 @@ /** * A VertexArray that is specialised to handle 16-bit array indices. - * Call Bind() and pass the return value to the indices parameter of - * glDrawElements/glDrawRangeElements/glMultiDrawElements. - * Use CVertexBuffer::Unbind() to unbind the array when done. + * Call UploadIfNeeded() before use in Draw/DrawIndexed. */ class VertexIndexArray : public VertexArray { Index: ps/trunk/source/renderer/VertexArray.cpp =================================================================== --- ps/trunk/source/renderer/VertexArray.cpp +++ ps/trunk/source/renderer/VertexArray.cpp @@ -291,13 +291,20 @@ Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { if (!m_VB) - return NULL; + return nullptr; - u8* base = m_VB->m_Owner->Bind(deviceCommandContext); - base += m_VB->m_Index*m_Stride; + UploadIfNeeded(deviceCommandContext); + m_VB->m_Owner->Bind(deviceCommandContext); + u8* base = nullptr; + base += m_VB->m_Index * m_Stride; return base; } +void VertexArray::UploadIfNeeded( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) +{ + m_VB->m_Owner->UploadIfNeeded(deviceCommandContext); +} // Free the backing store to save some memory void VertexArray::FreeBackingStore() Index: ps/trunk/source/renderer/VertexBuffer.h =================================================================== --- ps/trunk/source/renderer/VertexBuffer.h +++ ps/trunk/source/renderer/VertexBuffer.h @@ -102,6 +102,8 @@ /// to glVertexPointer ( + etc) calls u8* Bind(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); + void UploadIfNeeded(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); + /// Unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it static void Unbind( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); @@ -135,6 +137,8 @@ */ static bool UseStreaming(const bool dynamic); + Renderer::Backend::GL::CBuffer* GetBuffer() { return m_Buffer.get(); } + private: friend class CVertexBufferManager; // allow allocate only via CVertexBufferManager Index: ps/trunk/source/renderer/VertexBuffer.cpp =================================================================== --- ps/trunk/source/renderer/VertexBuffer.cpp +++ ps/trunk/source/renderer/VertexBuffer.cpp @@ -59,6 +59,10 @@ // address at most 64K of them with 16-bit indices size = std::min(size, vertexSize * 65536); } + else if (type == Renderer::Backend::GL::CBuffer::Type::INDEX) + { + ENSURE(vertexSize == sizeof(u16)); + } // store max/free vertex counts m_MaxVertices = m_FreeVertices = size / vertexSize; @@ -222,19 +226,13 @@ } } -/////////////////////////////////////////////////////////////////////////////// -// Bind: bind to this buffer; return pointer to address required as parameter -// to glVertexPointer ( + etc) calls -u8* CVertexBuffer::Bind( +void CVertexBuffer::UploadIfNeeded( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { if (UseStreaming(m_Buffer->IsDynamic())) { if (!m_HasNeededChunks) - { - deviceCommandContext->BindBuffer(m_Buffer->GetType(), m_Buffer.get()); - return nullptr; - } + return; // If any chunks are out of sync with the current VBO, and are // needed for rendering this frame, we'll need to re-upload the VBO @@ -290,8 +288,15 @@ m_HasNeededChunks = false; } - deviceCommandContext->BindBuffer(m_Buffer->GetType(), m_Buffer.get()); +} +// Bind: bind to this buffer; return pointer to address required as parameter +// to glVertexPointer ( + etc) calls +u8* CVertexBuffer::Bind( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) +{ + UploadIfNeeded(deviceCommandContext); + deviceCommandContext->BindBuffer(m_Buffer->GetType(), m_Buffer.get()); return nullptr; } Index: ps/trunk/source/renderer/WaterManager.cpp =================================================================== --- ps/trunk/source/renderer/WaterManager.cpp +++ ps/trunk/source/renderer/WaterManager.cpp @@ -812,9 +812,9 @@ shader->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff); shader->Uniform(str_width, (int)m_ShoreWaves[a]->m_Width); - u8* indexBase = m_ShoreWavesVBIndices->m_Owner->Bind(deviceCommandContext); - glDrawElements(GL_TRIANGLES, (GLsizei) (m_ShoreWaves[a]->m_Width-1)*(7*6), - GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_ShoreWavesVBIndices->m_Index)); + m_ShoreWavesVBIndices->m_Owner->UploadIfNeeded(deviceCommandContext); + deviceCommandContext->SetIndexBuffer(m_ShoreWavesVBIndices->m_Owner->GetBuffer()); + deviceCommandContext->DrawIndexed(m_ShoreWavesVBIndices->m_Index, (m_ShoreWaves[a]->m_Width - 1) * (7 * 6), 0); shader->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff + 6.0f); Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h @@ -85,6 +85,17 @@ void SetScissors(const uint32_t scissorCount, const Rect* scissors); void SetViewports(const uint32_t viewportCount, const Rect* viewports); + void SetIndexBuffer(CBuffer* buffer); + void SetIndexBufferData(const void* data); + + void Draw(const uint32_t firstVertex, const uint32_t vertexCount); + void DrawIndexed( + const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset); + // TODO: should be removed when performance impact is minimal on slow hardware. + void DrawIndexedInRange( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t start, const uint32_t end); + void BeginScopedLabel(const char* name); void EndScopedLabel(); @@ -116,6 +127,9 @@ uint32_t m_ScopedLabelDepth = 0; + CBuffer* m_IndexBuffer = nullptr; + const void* m_IndexBufferData = nullptr; + uint32_t m_ActiveTextureUnit = 0; using BindUnit = std::pair; std::array m_BoundTextures; Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -379,7 +379,13 @@ void CDeviceCommandContext::BindBuffer(const CBuffer::Type type, CBuffer* buffer) { - ENSURE(!buffer || type == buffer->GetType()); + ENSURE(!buffer || buffer->GetType() == type); + if (type == CBuffer::Type::INDEX) + { + if (!buffer) + m_IndexBuffer = nullptr; + m_IndexBufferData = nullptr; + } glBindBufferARB(BufferTypeToGLTarget(type), buffer ? buffer->GetHandle() : 0); } @@ -387,7 +393,12 @@ { ResetStates(); + m_IndexBuffer = nullptr; + m_IndexBufferData = nullptr; + BindTexture(0, GL_TEXTURE_2D, 0); + BindBuffer(CBuffer::Type::INDEX, nullptr); + BindBuffer(CBuffer::Type::VERTEX, nullptr); ENSURE(m_ScopedLabelDepth == 0); } @@ -711,6 +722,70 @@ glViewport(viewports[0].x, viewports[0].y, viewports[0].width, viewports[0].height); } +void CDeviceCommandContext::SetIndexBuffer(CBuffer* buffer) +{ + ENSURE(buffer->GetType() == CBuffer::Type::INDEX); + m_IndexBuffer = buffer; + m_IndexBufferData = nullptr; + BindBuffer(CBuffer::Type::INDEX, m_IndexBuffer); +} + +void CDeviceCommandContext::SetIndexBufferData(const void* data) +{ + if (m_IndexBuffer) + { + BindBuffer(CBuffer::Type::INDEX, nullptr); + m_IndexBuffer = nullptr; + } + m_IndexBufferData = data; +} + +void CDeviceCommandContext::Draw( + const uint32_t firstVertex, const uint32_t vertexCount) +{ + // Some drivers apparently don't like count = 0 in glDrawArrays here, so skip + // all drawing in that case. + if (vertexCount == 0) + return; + glDrawArrays(GL_TRIANGLES, firstVertex, vertexCount); +} + +void CDeviceCommandContext::DrawIndexed( + const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) +{ + if (indexCount == 0) + return; + ENSURE(m_IndexBuffer || m_IndexBufferData); + ENSURE(vertexOffset == 0); + if (m_IndexBuffer) + { + ENSURE(sizeof(uint16_t) * (firstIndex + indexCount) <= m_IndexBuffer->GetSize()); + } + // Don't use glMultiDrawElements here since it doesn't have a significant + // performance impact and it suffers from various driver bugs (e.g. it breaks + // in Mesa 7.10 swrast with index VBOs). + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, + static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex))); +} + +void CDeviceCommandContext::DrawIndexedInRange( + const uint32_t firstIndex, const uint32_t indexCount, + const uint32_t start, const uint32_t end) +{ + if (indexCount == 0) + return; + ENSURE(m_IndexBuffer || m_IndexBufferData); + const void* indices = + static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex)); + // Draw with DrawRangeElements where available, since it might be more + // efficient for slow hardware. +#if CONFIG2_GLES + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, indices); +#else + glDrawRangeElementsEXT(GL_TRIANGLES, start, end, indexCount, GL_UNSIGNED_SHORT, indices); +#endif +} + CDeviceCommandContext::ScopedBind::ScopedBind( CDeviceCommandContext* deviceCommandContext, const GLenum target, const GLuint handle)