1
0
forked from 0ad/0ad

Moves GL vertex and index buffer management to CDeviceCommandContext.

Tested By: Stan
Differential Revision: https://code.wildfiregames.com/D4493
This was SVN commit r26406.
This commit is contained in:
Vladislav Belov 2022-02-18 17:33:12 +00:00
parent 6a2a297c0e
commit cff79b421a
29 changed files with 631 additions and 263 deletions

View File

@ -122,7 +122,8 @@ static void inline addVertex(const MinimapUnitVertex& v,
} // anonymous namespace
CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation)
: m_Simulation(simulation), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW)
: m_Simulation(simulation), m_IndexArray(false),
m_VertexArray(Renderer::Backend::GL::CBuffer::Type::VERTEX, true)
{
// Register Relax NG validator.
CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng");
@ -146,10 +147,10 @@ CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation)
m_AttributeColor.elems = 4;
m_VertexArray.AddAttribute(&m_AttributeColor);
m_VertexArray.SetNumVertices(MAX_ENTITIES_DRAWN);
m_VertexArray.SetNumberOfVertices(MAX_ENTITIES_DRAWN);
m_VertexArray.Layout();
m_IndexArray.SetNumVertices(MAX_ENTITIES_DRAWN);
m_IndexArray.SetNumberOfVertices(MAX_ENTITIES_DRAWN);
m_IndexArray.Layout();
VertexArrayIterator<u16> index = m_IndexArray.GetIterator();
for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i)
@ -498,8 +499,8 @@ void CMiniMapTexture::RenderFinalTexture(
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
u8* indexBase = m_IndexArray.Bind();
u8* base = m_VertexArray.Bind();
u8* indexBase = m_IndexArray.Bind(deviceCommandContext);
u8* base = m_VertexArray.Bind(deviceCommandContext);
const GLsizei stride = (GLsizei)m_VertexArray.GetStride();
shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset);
@ -509,7 +510,7 @@ void CMiniMapTexture::RenderFinalTexture(
glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase);
g_Renderer.GetStats().m_DrawCalls++;
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
#if !CONFIG2_GLES
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);

View File

@ -32,8 +32,8 @@
CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
m_Type(type), m_Active(true), m_NextParticleIdx(0), m_EmissionRoundingError(0.f),
m_LastUpdateTime(type->m_Manager.GetCurrentTime()),
m_IndexArray(GL_STATIC_DRAW),
m_VertexArray(GL_DYNAMIC_DRAW),
m_IndexArray(false),
m_VertexArray(Renderer::Backend::GL::CBuffer::Type::VERTEX, true),
m_LastFrameNumber(-1)
{
// If we should start with particles fully emitted, pretend that we
@ -64,10 +64,10 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
m_AttributeColor.elems = 4;
m_VertexArray.AddAttribute(&m_AttributeColor);
m_VertexArray.SetNumVertices(m_Type->m_MaxParticles * 4);
m_VertexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 4);
m_VertexArray.Layout();
m_IndexArray.SetNumVertices(m_Type->m_MaxParticles * 6);
m_IndexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 6);
m_IndexArray.Layout();
VertexArrayIterator<u16> index = m_IndexArray.GetIterator();
for (u16 i = 0; i < m_Type->m_MaxParticles; ++i)
@ -196,15 +196,17 @@ void CParticleEmitter::Bind(
shader->BindTexture(str_baseTex, m_Type->m_Texture->GetBackendTexture());
}
void CParticleEmitter::RenderArray(const CShaderProgramPtr& shader)
void CParticleEmitter::RenderArray(
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();
u8* base = m_VertexArray.Bind();
u8* indexBase = m_IndexArray.Bind(deviceCommandContext);
u8* base = m_VertexArray.Bind(deviceCommandContext);
GLsizei stride = (GLsizei)m_VertexArray.GetStride();

View File

@ -128,7 +128,9 @@ public:
/**
* Draw the vertex array.
*/
void RenderArray(const CShaderProgramPtr& shader);
void RenderArray(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader);
/**
* Stop this emitter emitting new particles, and pass responsibility for rendering

View File

@ -198,7 +198,7 @@ void CDecalRData::RenderDecals(
{
lastVB = batch.vertices->m_Owner;
const GLsizei stride = sizeof(SDecalVertex);
SDecalVertex* base = (SDecalVertex*)batch.vertices->m_Owner->Bind();
SDecalVertex* base = (SDecalVertex*)batch.vertices->m_Owner->Bind(deviceCommandContext);
shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]);
@ -210,7 +210,7 @@ void CDecalRData::RenderDecals(
if (lastIB != batch.indices->m_Owner)
{
lastIB = batch.indices->m_Owner;
batch.indices->m_Owner->Bind();
batch.indices->m_Owner->Bind(deviceCommandContext);
}
u8* indexBase = nullptr;
@ -225,7 +225,7 @@ void CDecalRData::RenderDecals(
}
}
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
void CDecalRData::BuildVertexData()
@ -279,7 +279,11 @@ void CDecalRData::BuildVertexData()
}
if (!m_VBDecals || m_VBDecals->m_Count != vertices.size())
m_VBDecals = g_VBMan.AllocateChunk(sizeof(SDecalVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
{
m_VBDecals = g_VBMan.AllocateChunk(
sizeof(SDecalVertex), vertices.size(),
Renderer::Backend::GL::CBuffer::Type::VERTEX, false);
}
m_VBDecals->m_Owner->UpdateChunkVertices(m_VBDecals.Get(), vertices.data());
std::vector<u16> indices((i1 - i0) * (j1 - j0) * 6);
@ -317,6 +321,10 @@ void CDecalRData::BuildVertexData()
// Construct vertex buffer.
if (!m_VBDecalsIndices || m_VBDecalsIndices->m_Count != indices.size())
m_VBDecalsIndices = g_VBMan.AllocateChunk(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
{
m_VBDecalsIndices = g_VBMan.AllocateChunk(
sizeof(u16), indices.size(),
Renderer::Backend::GL::CBuffer::Type::INDEX, false);
}
m_VBDecalsIndices->m_Owner->UpdateChunkVertices(m_VBDecalsIndices.Get(), indices.data());
}

View File

@ -17,18 +17,17 @@
#include "precompiled.h"
#include "lib/bits.h"
#include "lib/ogl.h"
#include "lib/sysdep/rtl.h"
#include "maths/Vector3D.h"
#include "renderer/HWLightingModelRenderer.h"
#include "graphics/Color.h"
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
#include "graphics/ShaderProgram.h"
#include "renderer/HWLightingModelRenderer.h"
#include "lib/bits.h"
#include "lib/ogl.h"
#include "lib/sysdep/rtl.h"
#include "maths/Vector3D.h"
#include "renderer/Renderer.h"
#include "renderer/RenderModifiers.h"
#include "renderer/VertexArray.h"
@ -50,7 +49,8 @@ struct ShaderModelDef : public CModelDefRPrivate
ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef)
: m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
: m_IndexArray(false),
m_Array(Renderer::Backend::GL::CBuffer::Type::VERTEX, false)
{
size_t numVertices = mdef->GetNumVertices();
@ -62,7 +62,7 @@ ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef)
m_Array.AddAttribute(&m_UVs[i]);
}
m_Array.SetNumVertices(numVertices);
m_Array.SetNumberOfVertices(numVertices);
m_Array.Layout();
for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); ++i)
@ -74,7 +74,7 @@ ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef)
m_Array.Upload();
m_Array.FreeBackingStore();
m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces()*3);
m_IndexArray.Layout();
ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
m_IndexArray.Upload();
@ -91,7 +91,10 @@ struct ShaderModel : public CModelRData
VertexArray::Attribute m_Position;
VertexArray::Attribute m_Normal;
ShaderModel(const void* key) : CModelRData(key), m_Array(GL_DYNAMIC_DRAW) { }
ShaderModel(const void* key)
: CModelRData(key),
m_Array(Renderer::Backend::GL::CBuffer::Type::VERTEX, true)
{}
};
@ -140,7 +143,7 @@ CModelRData* ShaderModelVertexRenderer::CreateModelData(const void* key, CModel*
shadermodel->m_Normal.elems = 4;
shadermodel->m_Array.AddAttribute(&shadermodel->m_Normal);
shadermodel->m_Array.SetNumVertices(mdef->GetNumVertices());
shadermodel->m_Array.SetNumberOfVertices(mdef->GetNumVertices());
shadermodel->m_Array.Layout();
// Verify alignment
@ -180,20 +183,23 @@ void ShaderModelVertexRenderer::BeginPass(int streamflags)
}
// Cleanup one rendering pass
void ShaderModelVertexRenderer::EndPass(int UNUSED(streamflags))
void ShaderModelVertexRenderer::EndPass(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int UNUSED(streamflags))
{
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
// Prepare UV coordinates for this modeldef
void ShaderModelVertexRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def)
void ShaderModelVertexRenderer::PrepareModelDef(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, const CModelDef& def)
{
m->shadermodeldef = (ShaderModelDef*)def.GetRenderData(m);
ENSURE(m->shadermodeldef);
u8* base = m->shadermodeldef->m_Array.Bind();
u8* base = m->shadermodeldef->m_Array.Bind(deviceCommandContext);
GLsizei stride = (GLsizei)m->shadermodeldef->m_Array.GetStride();
if (streamflags & STREAM_UV0)
@ -205,15 +211,17 @@ void ShaderModelVertexRenderer::PrepareModelDef(const CShaderProgramPtr& shader,
// Render one model
void ShaderModelVertexRenderer::RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data)
void ShaderModelVertexRenderer::RenderModel(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data)
{
const CModelDefPtr& mdldef = model->GetModelDef();
ShaderModel* shadermodel = static_cast<ShaderModel*>(data);
u8* base = shadermodel->m_Array.Bind();
u8* base = shadermodel->m_Array.Bind(deviceCommandContext);
GLsizei stride = (GLsizei)shadermodel->m_Array.GetStride();
u8* indexBase = m->shadermodeldef->m_IndexArray.Bind();
u8* indexBase = m->shadermodeldef->m_IndexArray.Bind(deviceCommandContext);
if (streamflags & STREAM_POS)
shader->VertexPointer(3, GL_FLOAT, stride, base + shadermodel->m_Position.offset);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -36,14 +36,18 @@ public:
ShaderModelVertexRenderer();
~ShaderModelVertexRenderer();
// Implementations
CModelRData* CreateModelData(const void* key, CModel* model);
void UpdateModelData(CModel* model, CModelRData* data, int updateflags);
CModelRData* CreateModelData(const void* key, CModel* model) override;
void UpdateModelData(CModel* model, CModelRData* data, int updateflags) override;
void BeginPass(int streamflags);
void EndPass(int streamflags);
void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def);
void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data);
void BeginPass(int streamflags) override;
void EndPass(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int streamflags) override;
void PrepareModelDef(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) override;
void RenderModel(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) override;
protected:
struct ShaderModelRendererInternals;

View File

@ -56,7 +56,7 @@ struct IModelDef : public CModelDefRPrivate
IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateTangents)
: m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
: m_IndexArray(false), m_Array(Renderer::Backend::GL::CBuffer::Type::VERTEX, false)
{
size_t numVertices = mdef->GetNumVertices();
@ -129,7 +129,7 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
// Copy the model data to graphics memory:-
m_Array.SetNumVertices(numVertices2);
m_Array.SetNumberOfVertices(numVertices2);
m_Array.Layout();
VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>();
@ -181,7 +181,7 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
m_Array.Upload();
m_Array.FreeBackingStore();
m_IndexArray.SetNumVertices(mdef->GetNumFaces() * 3);
m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces() * 3);
m_IndexArray.Layout();
VertexArrayIterator<u16> Indices = m_IndexArray.GetIterator();
@ -203,7 +203,7 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
{
// Upload model without calculating tangents:-
m_Array.SetNumVertices(numVertices);
m_Array.SetNumberOfVertices(numVertices);
m_Array.Layout();
VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>();
@ -235,7 +235,7 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
m_Array.Upload();
m_Array.FreeBackingStore();
m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces()*3);
m_IndexArray.Layout();
ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
m_IndexArray.Upload();
@ -307,23 +307,27 @@ void InstancingModelRenderer::BeginPass(int streamflags)
}
// Cleanup rendering pass.
void InstancingModelRenderer::EndPass(int UNUSED(streamflags))
void InstancingModelRenderer::EndPass(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
int UNUSED(streamflags))
{
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
// Prepare UV coordinates for this modeldef
void InstancingModelRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def)
void InstancingModelRenderer::PrepareModelDef(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, const CModelDef& def)
{
m->imodeldef = (IModelDef*)def.GetRenderData(m);
ENSURE(m->imodeldef);
u8* base = m->imodeldef->m_Array.Bind();
u8* base = m->imodeldef->m_Array.Bind(deviceCommandContext);
GLsizei stride = (GLsizei)m->imodeldef->m_Array.GetStride();
m->imodeldefIndexBase = m->imodeldef->m_IndexArray.Bind();
m->imodeldefIndexBase = m->imodeldef->m_IndexArray.Bind(deviceCommandContext);
if (streamflags & STREAM_POS)
shader->VertexPointer(3, GL_FLOAT, stride, base + m->imodeldef->m_Position.offset);
@ -356,7 +360,9 @@ void InstancingModelRenderer::PrepareModelDef(const CShaderProgramPtr& shader, i
// Render one model
void InstancingModelRenderer::RenderModel(const CShaderProgramPtr& shader, int UNUSED(streamflags), CModel* model, CModelRData* UNUSED(data))
void InstancingModelRenderer::RenderModel(
Renderer::Backend::GL::CDeviceCommandContext* UNUSED(deviceCommandContext),
const CShaderProgramPtr& shader, int UNUSED(streamflags), CModel* model, CModelRData* UNUSED(data))
{
const CModelDefPtr& mdldef = model->GetModelDef();
@ -378,7 +384,7 @@ void InstancingModelRenderer::RenderModel(const CShaderProgramPtr& shader, int U
#if CONFIG2_GLES
glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase);
#else
glDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)m->imodeldef->m_Array.GetNumVertices()-1,
glDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)m->imodeldef->m_Array.GetNumberOfVertices()-1,
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase);
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2012 Wildfire Games.
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -43,9 +43,14 @@ public:
void UpdateModelData(CModel* model, CModelRData* data, int updateflags);
void BeginPass(int streamflags);
void EndPass(int streamflags);
void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def);
void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data);
void EndPass(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
int streamflags);
void PrepareModelDef(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, const CModelDef& def);
void RenderModel(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data);
protected:
InstancingModelRendererInternals* m;

View File

@ -704,7 +704,7 @@ void ShaderModelRenderer::Render(
if (newModeldef != currentModeldef)
{
currentModeldef = newModeldef;
m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef);
m->vertexRenderer->PrepareModelDef(deviceCommandContext, shader, streamflags, *currentModeldef);
}
// Bind all uniforms when any change
@ -753,11 +753,11 @@ void ShaderModelRenderer::Render(
CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
ENSURE(rdata->GetKey() == m->vertexRenderer.get());
m->vertexRenderer->RenderModel(shader, streamflags, model, rdata);
m->vertexRenderer->RenderModel(deviceCommandContext, shader, streamflags, model, rdata);
}
}
m->vertexRenderer->EndPass(streamflags);
m->vertexRenderer->EndPass(deviceCommandContext, streamflags);
currentTech->EndPass(pass);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2012 Wildfire Games.
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -25,6 +25,7 @@
#include "graphics/MeshManager.h"
#include "graphics/ShaderProgramPtr.h"
#include "renderer/backend/gl/DeviceCommandContext.h"
class CModel;
class CModelRData;
@ -114,7 +115,7 @@ public:
* This equals the streamflags parameter passed on the last call to
* BeginPass.
*/
virtual void EndPass(int streamflags) = 0;
virtual void EndPass(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int streamflags) = 0;
/**
@ -131,7 +132,9 @@ public:
* BeginPass.
* @param def The model definition.
*/
virtual void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) = 0;
virtual void PrepareModelDef(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) = 0;
/**
@ -153,7 +156,9 @@ public:
* that use the same CModelDef object and the same texture must
* succeed.
*/
virtual void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) = 0;
virtual void RenderModel(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) = 0;
};

View File

@ -154,7 +154,8 @@ struct OverlayRendererInternals
const float OverlayRenderer::OVERLAY_VOFFSET = 0.2f;
OverlayRendererInternals::OverlayRendererInternals()
: quadVertices(GL_DYNAMIC_DRAW), quadIndices(GL_STATIC_DRAW)
: quadVertices(Renderer::Backend::GL::CBuffer::Type::VERTEX, true),
quadIndices(false)
{
quadAttributePos.elems = 3;
quadAttributePos.type = GL_FLOAT;
@ -183,10 +184,10 @@ void OverlayRendererInternals::Initialize()
// only at this point can we safely allocate VBOs (in contrast to e.g. in the constructor),
// because their creation depends on the shader path, which is not reliably set before this point.
quadVertices.SetNumVertices(MAX_QUAD_OVERLAYS * 4);
quadVertices.SetNumberOfVertices(MAX_QUAD_OVERLAYS * 4);
quadVertices.Layout(); // allocate backing store
quadIndices.SetNumVertices(MAX_QUAD_OVERLAYS * 6);
quadIndices.SetNumberOfVertices(MAX_QUAD_OVERLAYS * 6);
quadIndices.Layout(); // allocate backing store
// Since the quads in the vertex array are independent and always consist of exactly 4 vertices per quad, the
@ -480,7 +481,7 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC
deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0);
deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, 0);
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
void OverlayRenderer::RenderTexturedOverlayLines(
@ -551,8 +552,8 @@ void OverlayRenderer::RenderQuadOverlays(
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();
u8* vertexBase = m->quadVertices.Bind();
u8* indexBase = m->quadIndices.Bind(deviceCommandContext);
u8* vertexBase = m->quadVertices.Bind(deviceCommandContext);
GLsizei indexStride = m->quadIndices.GetStride();
GLsizei vertexStride = m->quadVertices.GetStride();
@ -599,7 +600,7 @@ void OverlayRenderer::RenderQuadOverlays(
deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0);
deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, 0);
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
#if !CONFIG2_GLES
if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME)

View File

@ -158,13 +158,13 @@ void ParticleRenderer::RenderParticles(
shader->Uniform(str_modelViewMatrix, g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse());
}
emitter->Bind(deviceCommandContext, lastTech->GetShader());
emitter->RenderArray(lastTech->GetShader());
emitter->RenderArray(deviceCommandContext, lastTech->GetShader());
}
if (lastTech)
lastTech->EndPass();
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
void ParticleRenderer::RenderBounds(int cullGroup)

View File

@ -281,14 +281,20 @@ void CPatchRData::BuildBlends()
{
// Construct vertex buffer
m_VBBlends = g_VBMan.AllocateChunk(sizeof(SBlendVertex), blendVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN);
m_VBBlends = g_VBMan.AllocateChunk(
sizeof(SBlendVertex), blendVertices.size(),
Renderer::Backend::GL::CBuffer::Type::VERTEX, false,
nullptr, CVertexBufferManager::Group::TERRAIN);
m_VBBlends->m_Owner->UpdateChunkVertices(m_VBBlends.Get(), &blendVertices[0]);
// Update the indices to include the base offset of the vertex data
for (size_t k = 0; k < blendIndices.size(); ++k)
blendIndices[k] += static_cast<u16>(m_VBBlends->m_Index);
m_VBBlendIndices = g_VBMan.AllocateChunk(sizeof(u16), blendIndices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN);
m_VBBlendIndices = g_VBMan.AllocateChunk(
sizeof(u16), blendIndices.size(),
Renderer::Backend::GL::CBuffer::Type::INDEX, false,
nullptr, CVertexBufferManager::Group::TERRAIN);
m_VBBlendIndices->m_Owner->UpdateChunkVertices(m_VBBlendIndices.Get(), &blendIndices[0]);
}
}
@ -489,7 +495,9 @@ void CPatchRData::BuildIndices()
ENSURE(indices.size());
// Construct vertex buffer
m_VBBaseIndices = g_VBMan.AllocateChunk(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN);
m_VBBaseIndices = g_VBMan.AllocateChunk(
sizeof(u16), indices.size(),
Renderer::Backend::GL::CBuffer::Type::INDEX, false, nullptr, CVertexBufferManager::Group::TERRAIN);
m_VBBaseIndices->m_Owner->UpdateChunkVertices(m_VBBaseIndices.Get(), &indices[0]);
}
@ -532,7 +540,12 @@ void CPatchRData::BuildVertices()
// upload to vertex buffer
if (!m_VBBase)
m_VBBase = g_VBMan.AllocateChunk(sizeof(SBaseVertex), vsize * vsize, GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN);
{
m_VBBase = g_VBMan.AllocateChunk(
sizeof(SBaseVertex), vsize * vsize,
Renderer::Backend::GL::CBuffer::Type::VERTEX, false,
nullptr, CVertexBufferManager::Group::TERRAIN);
}
m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase.Get(), &vertices[0]);
}
@ -614,7 +627,12 @@ void CPatchRData::BuildSides()
return;
if (!m_VBSides)
m_VBSides = g_VBMan.AllocateChunk(sizeof(SSideVertex), sideVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::DEFAULT);
{
m_VBSides = g_VBMan.AllocateChunk(
sizeof(SSideVertex), sideVertices.size(),
Renderer::Backend::GL::CBuffer::Type::VERTEX, false,
nullptr, CVertexBufferManager::Group::DEFAULT);
}
m_VBSides->m_Owner->UpdateChunkVertices(m_VBSides.Get(), &sideVertices[0]);
}
@ -779,7 +797,7 @@ void CPatchRData::RenderBases(
for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv)
{
GLsizei stride = sizeof(SBaseVertex);
SBaseVertex *base = (SBaseVertex *)itv->first->Bind();
SBaseVertex *base = (SBaseVertex *)itv->first->Bind(deviceCommandContext);
shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]);
shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]);
@ -788,7 +806,7 @@ void CPatchRData::RenderBases(
for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it)
{
it->first->Bind();
it->first->Bind(deviceCommandContext);
BatchElements& batch = it->second;
@ -807,7 +825,7 @@ void CPatchRData::RenderBases(
}
}
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
/**
@ -1006,7 +1024,7 @@ void CPatchRData::RenderBlends(
lastVB = itv->first;
previousShader = shader;
GLsizei stride = sizeof(SBlendVertex);
SBlendVertex *base = (SBlendVertex *)itv->first->Bind();
SBlendVertex *base = (SBlendVertex *)itv->first->Bind(deviceCommandContext);
shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]);
@ -1018,7 +1036,7 @@ void CPatchRData::RenderBlends(
for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it)
{
it->first->Bind();
it->first->Bind(deviceCommandContext);
BatchElements& batch = it->second;
@ -1035,10 +1053,12 @@ void CPatchRData::RenderBlends(
}
}
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
void CPatchRData::RenderStreams(const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader, int streamflags)
void CPatchRData::RenderStreams(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader, int streamflags)
{
PROFILE3("render terrain streams");
@ -1074,7 +1094,7 @@ void CPatchRData::RenderStreams(const std::vector<CPatchRData*>& patches, const
for (const std::pair<CVertexBuffer* const, StreamIndexBufferBatches>& streamBatch : batches)
{
GLsizei stride = sizeof(SBaseVertex);
SBaseVertex *base = (SBaseVertex *)streamBatch.first->Bind();
SBaseVertex *base = (SBaseVertex *)streamBatch.first->Bind(deviceCommandContext);
shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position);
if (streamflags & STREAM_POSTOUV0)
@ -1086,7 +1106,7 @@ void CPatchRData::RenderStreams(const std::vector<CPatchRData*>& patches, const
for (const std::pair<CVertexBuffer* const, StreamBatchElements>& batchIndexBuffer : streamBatch.second)
{
batchIndexBuffer.first->Bind();
batchIndexBuffer.first->Bind(deviceCommandContext);
const StreamBatchElements& batch = batchIndexBuffer.second;
@ -1098,7 +1118,7 @@ void CPatchRData::RenderStreams(const std::vector<CPatchRData*>& patches, const
}
}
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
void CPatchRData::RenderOutline()
@ -1133,7 +1153,9 @@ void CPatchRData::RenderOutline()
g_Renderer.GetDebugRenderer().DrawLine(line, CColor(0.0f, 0.0f, 1.0f, 1.0f), 0.1f);
}
void CPatchRData::RenderSides(const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader)
void CPatchRData::RenderSides(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader)
{
PROFILE3("render terrain sides");
@ -1146,7 +1168,7 @@ void CPatchRData::RenderSides(const std::vector<CPatchRData*>& patches, const CS
if (lastVB != patch->m_VBSides->m_Owner)
{
lastVB = patch->m_VBSides->m_Owner;
SSideVertex *base = (SSideVertex*)patch->m_VBSides->m_Owner->Bind();
SSideVertex *base = (SSideVertex*)patch->m_VBSides->m_Owner->Bind(deviceCommandContext);
// setup data pointers
GLsizei stride = sizeof(SSideVertex);
@ -1162,7 +1184,7 @@ void CPatchRData::RenderSides(const std::vector<CPatchRData*>& patches, const CS
g_Renderer.m_Stats.m_TerrainTris += patch->m_VBSides->m_Count - 2;
}
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
void CPatchRData::RenderPriorities(CTextRenderer& textRenderer)
@ -1362,32 +1384,46 @@ void CPatchRData::BuildWater()
// No vertex buffers if no data generated
if (!water_indices.empty())
{
m_VBWater = g_VBMan.AllocateChunk(sizeof(SWaterVertex), water_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER);
m_VBWater = g_VBMan.AllocateChunk(
sizeof(SWaterVertex), water_vertex_data.size(),
Renderer::Backend::GL::CBuffer::Type::VERTEX, false,
nullptr, CVertexBufferManager::Group::WATER);
m_VBWater->m_Owner->UpdateChunkVertices(m_VBWater.Get(), &water_vertex_data[0]);
m_VBWaterIndices = g_VBMan.AllocateChunk(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER);
m_VBWaterIndices = g_VBMan.AllocateChunk(
sizeof(GLushort), water_indices.size(),
Renderer::Backend::GL::CBuffer::Type::INDEX, false,
nullptr, CVertexBufferManager::Group::WATER);
m_VBWaterIndices->m_Owner->UpdateChunkVertices(m_VBWaterIndices.Get(), &water_indices[0]);
}
if (!water_indices_shore.empty())
{
m_VBWaterShore = g_VBMan.AllocateChunk(sizeof(SWaterVertex), water_vertex_data_shore.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER);
m_VBWaterShore = g_VBMan.AllocateChunk(
sizeof(SWaterVertex), water_vertex_data_shore.size(),
Renderer::Backend::GL::CBuffer::Type::VERTEX, false,
nullptr, CVertexBufferManager::Group::WATER);
m_VBWaterShore->m_Owner->UpdateChunkVertices(m_VBWaterShore.Get(), &water_vertex_data_shore[0]);
// Construct indices buffer
m_VBWaterIndicesShore = g_VBMan.AllocateChunk(sizeof(GLushort), water_indices_shore.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER);
m_VBWaterIndicesShore = g_VBMan.AllocateChunk(
sizeof(GLushort), water_indices_shore.size(),
Renderer::Backend::GL::CBuffer::Type::INDEX, false,
nullptr, CVertexBufferManager::Group::WATER);
m_VBWaterIndicesShore->m_Owner->UpdateChunkVertices(m_VBWaterIndicesShore.Get(), &water_indices_shore[0]);
}
}
void CPatchRData::RenderWaterSurface(const CShaderProgramPtr& shader, const bool bindWaterData)
void CPatchRData::RenderWaterSurface(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, const bool bindWaterData)
{
ASSERT(m_UpdateFlags == 0);
if (!m_VBWater)
return;
SWaterVertex* base = reinterpret_cast<SWaterVertex*>(m_VBWater->m_Owner->Bind());
SWaterVertex* base = reinterpret_cast<SWaterVertex*>(m_VBWater->m_Owner->Bind(deviceCommandContext));
// Setup data pointers.
const GLsizei stride = sizeof(SWaterVertex);
@ -1397,7 +1433,7 @@ void CPatchRData::RenderWaterSurface(const CShaderProgramPtr& shader, const bool
shader->AssertPointersBound();
u8* indexBase = m_VBWaterIndices->m_Owner->Bind();
u8* indexBase = m_VBWaterIndices->m_Owner->Bind(deviceCommandContext);
glDrawElements(
GL_TRIANGLES, static_cast<GLsizei>(m_VBWaterIndices->m_Count),
GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndices->m_Index));
@ -1405,17 +1441,19 @@ void CPatchRData::RenderWaterSurface(const CShaderProgramPtr& shader, const bool
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndices->m_Count / 3;
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
void CPatchRData::RenderWaterShore(const CShaderProgramPtr& shader)
void CPatchRData::RenderWaterShore(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader)
{
ASSERT(m_UpdateFlags == 0);
if (!m_VBWaterShore)
return;
SWaterVertex* base = reinterpret_cast<SWaterVertex*>(m_VBWaterShore->m_Owner->Bind());
SWaterVertex* base = reinterpret_cast<SWaterVertex*>(m_VBWaterShore->m_Owner->Bind(deviceCommandContext));
const GLsizei stride = sizeof(SWaterVertex);
shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWaterShore->m_Index].m_Position);
@ -1423,12 +1461,12 @@ void CPatchRData::RenderWaterShore(const CShaderProgramPtr& shader)
shader->AssertPointersBound();
u8* indexBase = m_VBWaterIndicesShore->m_Owner->Bind();
u8* indexBase = m_VBWaterIndicesShore->m_Owner->Bind(deviceCommandContext);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_VBWaterIndicesShore->m_Count),
GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndicesShore->m_Index));
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndicesShore->m_Count / 3;
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}

View File

@ -48,8 +48,12 @@ public:
void RenderOutline();
void RenderPriorities(CTextRenderer& textRenderer);
void RenderWaterSurface(const CShaderProgramPtr& shader, const bool bindWaterData);
void RenderWaterShore(const CShaderProgramPtr& shader);
void RenderWaterSurface(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader, const bool bindWaterData);
void RenderWaterShore(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const CShaderProgramPtr& shader);
CPatch* GetPatch() { return m_Patch; }
@ -61,8 +65,12 @@ public:
static void RenderBlends(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow);
static void RenderStreams(const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader, int streamflags);
static void RenderSides(const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader);
static void RenderStreams(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader, int streamflags);
static void RenderSides(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader);
static void PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow);

View File

@ -186,7 +186,7 @@ void TerrainRenderer::RenderTerrainOverlayTexture(
debugOverlayShader->BindTexture(str_baseTex, texture);
debugOverlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection());
debugOverlayShader->Uniform(str_textureTransform, textureMatrix);
CPatchRData::RenderStreams(visiblePatches, debugOverlayShader, STREAM_POS | STREAM_POSTOUV0);
CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, debugOverlayShader, STREAM_POS | STREAM_POSTOUV0);
// To make the overlay visible over water, render an additional map-sized
// water-height patch.
@ -269,7 +269,7 @@ void TerrainRenderer::RenderTerrainShader(
shaderSolid->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection());
shaderSolid->Uniform(str_color, 0.0f, 0.0f, 0.0f, 1.0f);
CPatchRData::RenderSides(visiblePatches, shaderSolid);
CPatchRData::RenderSides(deviceCommandContext, visiblePatches, shaderSolid);
techSolid->EndPass();
@ -315,7 +315,7 @@ void TerrainRenderer::RenderPatches(
solidShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection());
solidShader->Uniform(str_color, color);
CPatchRData::RenderStreams(visiblePatches, solidShader, STREAM_POS);
CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, solidShader, STREAM_POS);
solidTech->EndPass();
#endif
}
@ -499,9 +499,9 @@ bool TerrainRenderer::RenderFancyWater(
for (CPatchRData* data : m->visiblePatches[cullGroup])
{
data->RenderWaterSurface(fancyWaterShader, true);
data->RenderWaterSurface(deviceCommandContext, fancyWaterShader, true);
if (waterManager.m_WaterFancyEffects)
data->RenderWaterShore(fancyWaterShader);
data->RenderWaterShore(deviceCommandContext, fancyWaterShader);
}
m->fancyWaterTech->EndPass();
@ -552,7 +552,7 @@ void TerrainRenderer::RenderSimpleWater(
for (size_t i = 0; i < visiblePatches.size(); ++i)
{
CPatchRData* data = visiblePatches[i];
data->RenderWaterSurface(waterSimpleShader, false);
data->RenderWaterSurface(deviceCommandContext, waterSimpleShader, false);
}
deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0);
@ -603,7 +603,7 @@ void TerrainRenderer::RenderWaterFoamOccluders(
dummyShader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection());
dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f);
for (CPatchRData* data : m->visiblePatches[cullGroup])
data->RenderWaterShore(dummyShader);
data->RenderWaterShore(deviceCommandContext, dummyShader);
dummyTech->EndPass();
deviceCommandContext->SetFramebuffer(

View File

@ -53,7 +53,8 @@ void CTexturedLineRData::Render(
shader->Uniform(str_objectColor, line.m_Color);
GLsizei stride = sizeof(CTexturedLineRData::SVertex);
CTexturedLineRData::SVertex* vertexBase = reinterpret_cast<CTexturedLineRData::SVertex*>(m_VB->m_Owner->Bind());
CTexturedLineRData::SVertex* vertexBase =
reinterpret_cast<CTexturedLineRData::SVertex*>(m_VB->m_Owner->Bind(deviceCommandContext));
if (streamFlags & STREAM_POS)
shader->VertexPointer(3, GL_FLOAT, stride, &vertexBase->m_Position[0]);
@ -64,7 +65,7 @@ void CTexturedLineRData::Render(
if (streamFlags & STREAM_UV1)
shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &vertexBase->m_UVs[0]);
u8* indexBase = m_VBIndices->m_Owner->Bind();
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);
@ -309,7 +310,8 @@ void CTexturedLineRData::Update(const SOverlayTexturedLine& line)
for (const SVertex& vertex : vertices)
m_BoundingBox += vertex.m_Position;
m_VB = g_VBMan.AllocateChunk(sizeof(SVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
m_VB = g_VBMan.AllocateChunk(
sizeof(SVertex), vertices.size(), Renderer::Backend::GL::CBuffer::Type::VERTEX, false);
if (m_VB) // allocation might fail (e.g. due to too many vertices)
{
m_VB->m_Owner->UpdateChunkVertices(m_VB.Get(), &vertices[0]); // copy data into VBO
@ -317,7 +319,8 @@ void CTexturedLineRData::Update(const SOverlayTexturedLine& line)
for (size_t k = 0; k < indices.size(); ++k)
indices[k] += static_cast<u16>(m_VB->m_Index);
m_VBIndices = g_VBMan.AllocateChunk(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
m_VBIndices = g_VBMan.AllocateChunk(
sizeof(u16), indices.size(), Renderer::Backend::GL::CBuffer::Type::INDEX, false);
if (m_VBIndices)
m_VBIndices->m_Owner->UpdateChunkVertices(m_VBIndices.Get(), &indices[0]);
}

View File

@ -30,11 +30,11 @@
#include "renderer/VertexBufferManager.h"
VertexArray::VertexArray(GLenum usage, GLenum target)
VertexArray::VertexArray(
const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic)
: m_Type(type), m_Dynamic(dynamic)
{
m_Usage = usage;
m_Target = target;
m_NumVertices = 0;
m_NumberOfVertices = 0;
m_BackingStore = 0;
m_Stride = 0;
@ -55,13 +55,13 @@ void VertexArray::Free()
}
// Set the number of vertices stored in the array
void VertexArray::SetNumVertices(size_t num)
void VertexArray::SetNumberOfVertices(const size_t numberOfVertices)
{
if (num == m_NumVertices)
if (numberOfVertices == m_NumberOfVertices)
return;
Free();
m_NumVertices = num;
m_NumberOfVertices = numberOfVertices;
}
// Add vertex attributes like Position, Normal, UV
@ -215,8 +215,6 @@ void VertexArray::Layout()
m_Stride = 0;
//debug_printf("Layouting VertexArray\n");
for (ssize_t idx = m_Attributes.size()-1; idx >= 0; --idx)
{
Attribute* attr = m_Attributes[idx];
@ -250,19 +248,15 @@ void VertexArray::Layout()
m_Stride += attrSize;
if (m_Target == GL_ARRAY_BUFFER)
if (m_Type == Renderer::Backend::GL::CBuffer::Type::VERTEX)
m_Stride = Align<4>(m_Stride);
//debug_printf("%i: offset: %u\n", idx, attr->offset);
}
if (m_Target == GL_ARRAY_BUFFER)
if (m_Type == Renderer::Backend::GL::CBuffer::Type::VERTEX)
m_Stride = RoundStride(m_Stride);
//debug_printf("Stride: %u\n", m_Stride);
if (m_Stride)
m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumVertices, 16);
m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumberOfVertices, 16);
}
void VertexArray::PrepareForRendering()
@ -277,7 +271,10 @@ void VertexArray::Upload()
ENSURE(m_BackingStore);
if (!m_VB)
m_VB = g_VBMan.AllocateChunk(m_Stride, m_NumVertices, m_Usage, m_Target, m_BackingStore);
{
m_VB = g_VBMan.AllocateChunk(
m_Stride, m_NumberOfVertices, m_Type, m_Dynamic, m_BackingStore);
}
if (!m_VB)
{
@ -290,12 +287,13 @@ void VertexArray::Upload()
// Bind this array, returns the base address for calls to glVertexPointer etc.
u8* VertexArray::Bind()
u8* VertexArray::Bind(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
{
if (!m_VB)
return NULL;
u8* base = m_VB->m_Owner->Bind();
u8* base = m_VB->m_Owner->Bind(deviceCommandContext);
base += m_VB->m_Index*m_Stride;
return base;
}
@ -305,16 +303,14 @@ u8* VertexArray::Bind()
void VertexArray::FreeBackingStore()
{
// In streaming modes, the backing store must be retained
ENSURE(!CVertexBuffer::UseStreaming(m_Usage));
ENSURE(!CVertexBuffer::UseStreaming(m_Dynamic));
rtl_FreeAligned(m_BackingStore);
m_BackingStore = 0;
}
VertexIndexArray::VertexIndexArray(GLenum usage) :
VertexArray(usage, GL_ELEMENT_ARRAY_BUFFER)
VertexIndexArray::VertexIndexArray(const bool dynamic) :
VertexArray(Renderer::Backend::GL::CBuffer::Type::INDEX, dynamic)
{
m_Attr.type = GL_UNSIGNED_SHORT;
m_Attr.elems = 1;

View File

@ -18,6 +18,8 @@
#ifndef INCLUDED_VERTEXARRAY
#define INCLUDED_VERTEXARRAY
#include "renderer/backend/gl/Buffer.h"
#include "renderer/backend/gl/DeviceCommandContext.h"
#include "renderer/VertexBufferManager.h"
#include <vector>
@ -159,15 +161,16 @@ public:
};
public:
VertexArray(GLenum usage, GLenum target = GL_ARRAY_BUFFER);
VertexArray(
const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic);
~VertexArray();
// Set the number of vertices stored in the array
void SetNumVertices(size_t num);
void SetNumberOfVertices(const size_t numberOfVertices);
// Add vertex attributes
void AddAttribute(Attribute* attr);
size_t GetNumVertices() const { return m_NumVertices; }
size_t GetNumberOfVertices() const { return m_NumberOfVertices; }
size_t GetStride() const { return m_Stride; }
// Layout the vertex array format and create backing buffer in RAM.
@ -181,7 +184,7 @@ public:
// 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();
u8* Bind(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.
@ -197,9 +200,9 @@ private:
return VertexArrayIterator<T>(m_BackingStore + attr->offset, m_Stride);
}
GLenum m_Usage;
GLenum m_Target;
size_t m_NumVertices;
Renderer::Backend::GL::CBuffer::Type m_Type;
bool m_Dynamic;
size_t m_NumberOfVertices;
std::vector<Attribute*> m_Attributes;
CVertexBufferManager::Handle m_VB;
@ -216,7 +219,7 @@ private:
class VertexIndexArray : public VertexArray
{
public:
VertexIndexArray(GLenum usage);
VertexIndexArray(const bool dynamic);
/// Gets the iterator over the (only) attribute in this array, i.e. a u16.
VertexArrayIterator<u16> GetIterator() const;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -21,11 +21,14 @@
#include "lib/ogl.h"
#include "lib/sysdep/cpu.h"
#include "Renderer.h"
#include "ps/CLogger.h"
#include "ps/Errors.h"
#include "ps/VideoMode.h"
#include "renderer/backend/gl/Device.h"
#include "renderer/Renderer.h"
#include <algorithm>
#include <cstring>
#include <iterator>
// Absolute maximum (bytewise) size of each GL vertex buffer object.
@ -34,32 +37,34 @@
// TODO: measure what influence this has on performance
constexpr std::size_t MAX_VB_SIZE_BYTES = 4 * 1024 * 1024;
CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target)
: CVertexBuffer(vertexSize, usage, target, MAX_VB_SIZE_BYTES)
CVertexBuffer::CVertexBuffer(
const char* name, const size_t vertexSize,
const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic)
: CVertexBuffer(name, vertexSize, type, dynamic, MAX_VB_SIZE_BYTES)
{
}
CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target, size_t maximumBufferSize)
: m_VertexSize(vertexSize), m_Handle(0), m_Usage(usage), m_Target(target), m_HasNeededChunks(false)
CVertexBuffer::CVertexBuffer(
const char* name, const size_t vertexSize,
const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic,
const size_t maximumBufferSize)
: m_VertexSize(vertexSize), m_HasNeededChunks(false)
{
size_t size = maximumBufferSize;
if (target == GL_ARRAY_BUFFER) // vertex data buffer
if (type == Renderer::Backend::GL::CBuffer::Type::VERTEX)
{
// We want to store 16-bit indices to any vertex in a buffer, so the
// buffer must never be bigger than vertexSize*64K bytes since we can
// address at most 64K of them with 16-bit indices
size = std::min(size, vertexSize*65536);
size = std::min(size, vertexSize * 65536);
}
// store max/free vertex counts
m_MaxVertices = m_FreeVertices = size / vertexSize;
// allocate raw buffer
glGenBuffersARB(1, &m_Handle);
glBindBufferARB(m_Target, m_Handle);
glBufferDataARB(m_Target, m_MaxVertices * m_VertexSize, 0, m_Usage);
glBindBufferARB(m_Target, 0);
m_Buffer = g_VideoMode.GetBackendDevice()->CreateBuffer(
name, type, m_MaxVertices * m_VertexSize, dynamic);
// create sole free chunk
VBChunk* chunk = new VBChunk;
@ -74,46 +79,50 @@ CVertexBuffer::~CVertexBuffer()
// Must have released all chunks before destroying the buffer
ENSURE(m_AllocList.empty());
if (m_Handle)
glDeleteBuffersARB(1, &m_Handle);
m_Buffer.reset();
for (VBChunk* const& chunk : m_FreeList)
delete chunk;
}
bool CVertexBuffer::CompatibleVertexType(size_t vertexSize, GLenum usage, GLenum target) const
bool CVertexBuffer::CompatibleVertexType(
const size_t vertexSize, const Renderer::Backend::GL::CBuffer::Type type,
const bool dynamic) const
{
return usage == m_Usage && target == m_Target && vertexSize == m_VertexSize;
ENSURE(m_Buffer);
return type == m_Buffer->GetType() && dynamic == m_Buffer->IsDynamic() && vertexSize == m_VertexSize;
}
///////////////////////////////////////////////////////////////////////////////
// Allocate: try to allocate a buffer of given number of vertices (each of
// given size), with the given type, and using the given texture - return null
// if no free chunks available
CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore)
CVertexBuffer::VBChunk* CVertexBuffer::Allocate(
const size_t vertexSize, const size_t numberOfVertices,
const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic,
void* backingStore)
{
// check this is the right kind of buffer
if (!CompatibleVertexType(vertexSize, usage, target))
if (!CompatibleVertexType(vertexSize, type, dynamic))
return nullptr;
if (UseStreaming(usage))
if (UseStreaming(dynamic))
ENSURE(backingStore != nullptr);
// quick check there's enough vertices spare to allocate
if (numVertices > m_FreeVertices)
if (numberOfVertices > m_FreeVertices)
return nullptr;
// trawl free list looking for first free chunk with enough space
std::vector<VBChunk*>::iterator best_iter = m_FreeList.end();
for (std::vector<VBChunk*>::iterator iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter)
{
if (numVertices == (*iter)->m_Count)
if (numberOfVertices == (*iter)->m_Count)
{
best_iter = iter;
break;
}
else if (numVertices < (*iter)->m_Count && (best_iter == m_FreeList.end() || (*best_iter)->m_Count < (*iter)->m_Count))
else if (numberOfVertices < (*iter)->m_Count && (best_iter == m_FreeList.end() || (*best_iter)->m_Count < (*iter)->m_Count))
best_iter = iter;
}
@ -131,17 +140,17 @@ CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize, size_t numVer
// split chunk into two; - allocate a new chunk using all unused vertices in the
// found chunk, and add it to the free list
if (chunk->m_Count > numVertices)
if (chunk->m_Count > numberOfVertices)
{
VBChunk* newchunk = new VBChunk;
newchunk->m_Owner = this;
newchunk->m_Count = chunk->m_Count - numVertices;
newchunk->m_Index = chunk->m_Index + numVertices;
newchunk->m_Count = chunk->m_Count - numberOfVertices;
newchunk->m_Index = chunk->m_Index + numberOfVertices;
m_FreeList.emplace_back(newchunk);
m_FreeVertices += newchunk->m_Count;
// resize given chunk
chunk->m_Count = numVertices;
chunk->m_Count = numberOfVertices;
}
// return found chunk
@ -195,8 +204,8 @@ void CVertexBuffer::Release(VBChunk* chunk)
// UpdateChunkVertices: update vertex data for given chunk
void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk, void* data)
{
ENSURE(m_Handle);
if (UseStreaming(m_Usage))
ENSURE(m_Buffer);
if (UseStreaming(m_Buffer->IsDynamic()))
{
// The VBO is now out of sync with the backing store
chunk->m_Dirty = true;
@ -207,23 +216,24 @@ void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk, void* data)
}
else
{
glBindBufferARB(m_Target, m_Handle);
glBufferSubDataARB(m_Target, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize, data);
glBindBufferARB(m_Target, 0);
g_Renderer.GetDeviceCommandContext()->UploadBufferRegion(
m_Buffer.get(), data, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize);
}
}
///////////////////////////////////////////////////////////////////////////////
// Bind: bind to this buffer; return pointer to address required as parameter
// to glVertexPointer ( + etc) calls
u8* CVertexBuffer::Bind()
u8* CVertexBuffer::Bind(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
{
glBindBufferARB(m_Target, m_Handle);
if (UseStreaming(m_Usage))
if (UseStreaming(m_Buffer->IsDynamic()))
{
if (!m_HasNeededChunks)
{
deviceCommandContext->BindBuffer(m_Buffer->GetType(), m_Buffer.get());
return nullptr;
}
// 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
@ -239,29 +249,13 @@ u8* CVertexBuffer::Bind()
if (needUpload)
{
// Tell the driver that it can reallocate the whole VBO
glBufferDataARB(m_Target, m_MaxVertices * m_VertexSize, NULL, m_Usage);
// (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used
// here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with
// current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do
// the explicit glBufferData.)
while (true)
deviceCommandContext->UploadBuffer(m_Buffer.get(), [&](u8* mappedData)
{
void* p = glMapBufferARB(m_Target, GL_WRITE_ONLY);
if (p == NULL)
{
// This shouldn't happen unless we run out of virtual address space
LOGERROR("glMapBuffer failed");
break;
}
#ifndef NDEBUG
// To help detect bugs where PrepareForRendering() was not called,
// force all not-needed data to 0, so things won't get rendered
// with undefined (but possibly still correct-looking) data.
memset(p, 0, m_MaxVertices * m_VertexSize);
memset(mappedData, 0, m_MaxVertices * m_VertexSize);
#endif
// Copy only the chunks we need. (This condition is helpful when
@ -270,15 +264,8 @@ u8* CVertexBuffer::Bind()
// the rest.)
for (VBChunk* const& chunk : m_AllocList)
if (chunk->m_Needed)
memcpy((u8 *)p + chunk->m_Index * m_VertexSize, chunk->m_BackingStore, chunk->m_Count * m_VertexSize);
if (glUnmapBufferARB(m_Target) == GL_TRUE)
break;
// Unmap might fail on e.g. resolution switches, so just try again
// and hope it will eventually succeed
debug_printf("glUnmapBuffer failed, trying again...\n");
}
std::memcpy(mappedData + chunk->m_Index * m_VertexSize, chunk->m_BackingStore, chunk->m_Count * m_VertexSize);
});
// Anything we just uploaded is clean; anything else is dirty
// since the rest of the VBO content is now undefined
@ -302,14 +289,18 @@ u8* CVertexBuffer::Bind()
m_HasNeededChunks = false;
}
deviceCommandContext->BindBuffer(m_Buffer->GetType(), m_Buffer.get());
return nullptr;
}
void CVertexBuffer::Unbind()
void CVertexBuffer::Unbind(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
{
glBindBufferARB(GL_ARRAY_BUFFER, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0);
deviceCommandContext->BindBuffer(
Renderer::Backend::GL::CBuffer::Type::VERTEX, nullptr);
deviceCommandContext->BindBuffer(
Renderer::Backend::GL::CBuffer::Type::INDEX, nullptr);
}
size_t CVertexBuffer::GetBytesReserved() const
@ -335,9 +326,9 @@ void CVertexBuffer::DumpStatus() const
debug_printf("max size = %d\n", static_cast<int>(maxSize));
}
bool CVertexBuffer::UseStreaming(GLenum usage)
bool CVertexBuffer::UseStreaming(const bool dynamic)
{
return usage == GL_DYNAMIC_DRAW || usage == GL_STREAM_DRAW;
return dynamic;
}
void CVertexBuffer::PrepareForRendering(VBChunk* chunk)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -22,8 +22,10 @@
#ifndef INCLUDED_VERTEXBUFFER
#define INCLUDED_VERTEXBUFFER
#include "lib/ogl.h"
#include "renderer/backend/gl/Buffer.h"
#include "renderer/backend/gl/DeviceCommandContext.h"
#include <memory>
#include <vector>
/**
@ -87,16 +89,22 @@ public:
public:
// constructor, destructor
CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target);
CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target, size_t maximumBufferSize);
CVertexBuffer(
const char* name, const size_t vertexSize,
const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic);
CVertexBuffer(
const char* name, const size_t vertexSize,
const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic,
const size_t maximumBufferSize);
~CVertexBuffer();
/// Bind to this buffer; return pointer to address required as parameter
/// to glVertexPointer ( + etc) calls
u8* Bind();
u8* Bind(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext);
/// Unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it
static void Unbind();
static void Unbind(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext);
/// Make the vertex data available for the next call to Bind()
void PrepareForRendering(VBChunk* chunk);
@ -109,7 +117,9 @@ public:
size_t GetBytesAllocated() const;
/// Returns true if this vertex buffer is compatible with the specified vertex type and intended usage.
bool CompatibleVertexType(size_t vertexSize, GLenum usage, GLenum target) const;
bool CompatibleVertexType(
const size_t vertexSize, const Renderer::Backend::GL::CBuffer::Type type,
const bool dynamic) const;
void DumpStatus() const;
@ -120,23 +130,23 @@ public:
* so we will re-upload the entire buffer every frame using glMapBuffer.
* This requires the buffer's owner to hold onto its backing store.
*
* If false, we assume it will change rarely, and use glSubBufferData to
* If false, we assume it will change rarely, and use direct upload to
* update it incrementally. The backing store can be freed to save memory.
*/
static bool UseStreaming(GLenum usage);
static bool UseStreaming(const bool dynamic);
protected:
private:
friend class CVertexBufferManager; // allow allocate only via CVertexBufferManager
/// Try to allocate a buffer of given number of vertices (each of given size),
/// and with the given type - return null if no free chunks available
VBChunk* Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore);
VBChunk* Allocate(
const size_t vertexSize, const size_t numberOfVertices,
const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic,
void* backingStore);
/// Return given chunk to this buffer
void Release(VBChunk* chunk);
private:
/// Vertex size of this vertex buffer
size_t m_VertexSize;
/// Number of vertices of above size in this buffer
@ -147,13 +157,10 @@ private:
std::vector<VBChunk*> m_AllocList;
/// Available free vertices - total of all free vertices in the free list
size_t m_FreeVertices;
/// Handle to the actual GL vertex buffer object
GLuint m_Handle;
/// Usage type of the buffer (GL_STATIC_DRAW etc)
GLenum m_Usage;
/// Buffer target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER)
GLenum m_Target;
std::unique_ptr<Renderer::Backend::GL::CBuffer> m_Buffer;
bool m_HasNeededChunks;
};
#endif
#endif // INCLUDED_VERTEXBUFFER

View File

@ -74,15 +74,14 @@ void CVertexBufferManager::Shutdown()
* given size), with the given type, and using the given texture - return null
* if no free chunks available
*/
CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore, Group group)
CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk(
const size_t vertexSize, const size_t numberOfVertices,
const Renderer::Backend::GL::CBuffer::Type type,
const bool dynamic, void* backingStore, Group group)
{
CVertexBuffer::VBChunk* result = nullptr;
ENSURE(usage == GL_STREAM_DRAW || usage == GL_STATIC_DRAW || usage == GL_DYNAMIC_DRAW);
ENSURE(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER);
if (CVertexBuffer::UseStreaming(usage))
if (CVertexBuffer::UseStreaming(dynamic))
ENSURE(backingStore != NULL);
// TODO, RC - run some sanity checks on allocation request
@ -93,7 +92,7 @@ CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk(size_t vertexSi
debug_printf("\n============================\n# allocate vsize=%zu nverts=%zu\n\n", vertexSize, numVertices);
for (const std::unique_ptr<CVertexBuffer>& buffer : buffers)
{
if (buffer->CompatibleVertexType(vertexSize, usage, target))
if (buffer->CompatibleVertexType(vertexSize, type, dynamic))
{
debug_printf("%p\n", buffer.get());
buffer->DumpStatus();
@ -105,7 +104,7 @@ CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk(size_t vertexSi
// satisfy the allocation
for (const std::unique_ptr<CVertexBuffer>& buffer : buffers)
{
result = buffer->Allocate(vertexSize, numVertices, usage, target, backingStore);
result = buffer->Allocate(vertexSize, numberOfVertices, type, dynamic, backingStore);
if (result)
return Handle(result);
}
@ -113,14 +112,14 @@ CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk(size_t vertexSi
// got this far; need to allocate a new buffer
buffers.emplace_back(
group == Group::DEFAULT
? std::make_unique<CVertexBuffer>(vertexSize, usage, target)
? std::make_unique<CVertexBuffer>("VertexBuffer (Default)", vertexSize, type, dynamic)
// Reduces the buffer size for not so frequent buffers.
: std::make_unique<CVertexBuffer>(vertexSize, usage, target, 1024 * 1024));
result = buffers.back()->Allocate(vertexSize, numVertices, usage, target, backingStore);
: std::make_unique<CVertexBuffer>("VertexBuffer", vertexSize, type, dynamic, 1024 * 1024));
result = buffers.back()->Allocate(vertexSize, numberOfVertices, type, dynamic, backingStore);
if (!result)
{
LOGERROR("Failed to create VBOs (%zu*%zu)", vertexSize, numVertices);
LOGERROR("Failed to create VBOs (%zu*%zu)", vertexSize, numberOfVertices);
return Handle();
}

View File

@ -88,7 +88,10 @@ public:
* lifetime of the VBChunk
* @return chunk, or empty handle if no free chunks available
*/
Handle AllocateChunk(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore = nullptr, Group group = Group::DEFAULT);
Handle AllocateChunk(
const size_t vertexSize, const size_t numberOfVertices,
const Renderer::Backend::GL::CBuffer::Type type,
const bool dynamic, void* backingStore = nullptr, Group group = Group::DEFAULT);
/// Returns the given @p chunk to its owning buffer
void Release(CVertexBuffer::VBChunk* chunk);

View File

@ -532,7 +532,7 @@ void WaterManager::CreateWaveMeshes()
// Generic indexes, max-length
m_ShoreWavesVBIndices = g_VBMan.AllocateChunk(
sizeof(GLushort), water_indices.size(),
GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER,
Renderer::Backend::GL::CBuffer::Type::INDEX, false,
nullptr, CVertexBufferManager::Group::WATER);
m_ShoreWavesVBIndices->m_Owner->UpdateChunkVertices(m_ShoreWavesVBIndices.Get(), &water_indices[0]);
@ -753,7 +753,7 @@ void WaterManager::CreateWaveMeshes()
shoreWave->m_VBVertices = g_VBMan.AllocateChunk(
sizeof(SWavesVertex), vertices.size(),
GL_STATIC_DRAW, GL_ARRAY_BUFFER,
Renderer::Backend::GL::CBuffer::Type::VERTEX, false,
nullptr, CVertexBufferManager::Group::WATER);
shoreWave->m_VBVertices->m_Owner->UpdateChunkVertices(shoreWave->m_VBVertices.Get(), &vertices[0]);
@ -798,7 +798,7 @@ void WaterManager::RenderWaves(
continue;
CVertexBuffer::VBChunk* VBchunk = m_ShoreWaves[a]->m_VBVertices.Get();
SWavesVertex* base = (SWavesVertex*)VBchunk->m_Owner->Bind();
SWavesVertex* base = (SWavesVertex*)VBchunk->m_Owner->Bind(deviceCommandContext);
// setup data pointers
GLsizei stride = sizeof(SWavesVertex);
@ -815,7 +815,7 @@ void WaterManager::RenderWaves(
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();
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));
@ -825,7 +825,7 @@ void WaterManager::RenderWaves(
//g_Renderer.m_Stats.m_DrawCalls++;
//g_Renderer.m_Stats.m_WaterTris += m_ShoreWaves_VBIndices->m_Count / 3;
CVertexBuffer::Unbind();
CVertexBuffer::Unbind(deviceCommandContext);
}
tech->EndPass();
deviceCommandContext->SetFramebuffer(

View File

@ -0,0 +1,73 @@
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "Buffer.h"
#include "lib/code_annotation.h"
#include "lib/config2.h"
#include "ps/CLogger.h"
#include "ps/ConfigDB.h"
#include "renderer/backend/gl/Device.h"
#include "renderer/backend/gl/Texture.h"
namespace Renderer
{
namespace Backend
{
namespace GL
{
// static
std::unique_ptr<CBuffer> CBuffer::Create(
CDevice* device, const char* name,
const Type type, const uint32_t size, const bool dynamic)
{
std::unique_ptr<CBuffer> buffer(new CBuffer());
buffer->m_Device = device;
buffer->m_Type = type;
buffer->m_Size = size;
buffer->m_Dynamic = dynamic;
glGenBuffersARB(1, &buffer->m_Handle);
const GLenum target = type == Type::INDEX ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
glBindBufferARB(target, buffer->m_Handle);
glBufferDataARB(target, size, nullptr, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
#if KHR_DEBUG_ENABLED && !CONFIG2_GLES
glObjectLabel(GL_BUFFER, buffer->m_Handle, -1, name);
#else
UNUSED2(name);
#endif
glBindBufferARB(target, 0);
return buffer;
}
CBuffer::CBuffer() = default;
CBuffer::~CBuffer()
{
if (m_Handle)
glDeleteBuffersARB(1, &m_Handle);
}
} // namespace GL
} // namespace Backend
} // namespace Renderer

View File

@ -0,0 +1,76 @@
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_RENDERER_BACKEND_GL_BUFFER
#define INCLUDED_RENDERER_BACKEND_GL_BUFFER
#include "lib/ogl.h"
#include <cstdint>
#include <memory>
namespace Renderer
{
namespace Backend
{
namespace GL
{
class CDevice;
class CBuffer
{
public:
enum class Type
{
VERTEX,
INDEX
};
~CBuffer();
Type GetType() const { return m_Type; }
uint32_t GetSize() const { return m_Size; }
bool IsDynamic() const { return m_Dynamic; }
GLuint GetHandle() { return m_Handle; }
private:
friend class CDevice;
static std::unique_ptr<CBuffer> Create(
CDevice* device, const char* name,
const Type type, const uint32_t size, const bool dynamic);
CBuffer();
CDevice* m_Device = nullptr;
Type m_Type = Type::VERTEX;
uint32_t m_Size = 0;
bool m_Dynamic = false;
GLuint m_Handle = 0;
};
} // namespace GL
} // namespace Backend
} // namespace Renderer
#endif // INCLUDED_RENDERER_BACKEND_GL_BUFFER

View File

@ -213,6 +213,10 @@ std::unique_ptr<CDevice> CDevice::Create(SDL_Window* window, const bool arb)
// and irrelevant (was never widespread).
capabilities.S3TC = ogl_HaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", nullptr) == 0;
#endif
#if CONFIG2_GLES
capabilities.multisampling = false;
capabilities.maxSampleCount = 1;
#else
capabilities.multisampling =
ogl_HaveVersion(3, 3) &&
ogl_HaveExtension("GL_ARB_multisample") &&
@ -223,6 +227,7 @@ std::unique_ptr<CDevice> CDevice::Create(SDL_Window* window, const bool arb)
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
capabilities.maxSampleCount = maxSamples;
}
#endif
capabilities.anisotropicFiltering = ogl_HaveExtension("GL_EXT_texture_filter_anisotropic");
if (capabilities.anisotropicFiltering)
{
@ -652,6 +657,12 @@ std::unique_ptr<CTexture> CDevice::CreateTexture2D(const char* name,
format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
}
std::unique_ptr<CBuffer> CDevice::CreateBuffer(
const char* name, const CBuffer::Type type, const uint32_t size, const bool dynamic)
{
return CBuffer::Create(this, name, type, size, dynamic);
}
void CDevice::Present()
{
if (m_Window)

View File

@ -19,7 +19,9 @@
#define INCLUDED_RENDERER_BACKEND_GL_DEVICE
#include "renderer/backend/Format.h"
#include "renderer/backend/gl/Buffer.h"
#include "renderer/backend/gl/Framebuffer.h"
#include "renderer/backend/gl/Texture.h"
#include "scriptinterface/ScriptForward.h"
#include <memory>
@ -39,7 +41,6 @@ namespace GL
{
class CDeviceCommandContext;
class CTexture;
class CDevice
{
@ -83,6 +84,9 @@ public:
const Format format, const uint32_t width, const uint32_t height,
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1);
std::unique_ptr<CBuffer> CreateBuffer(
const char* name, const CBuffer::Type type, const uint32_t size, const bool dynamic);
void Present();
bool IsFormatSupported(const Format format) const;

View File

@ -19,12 +19,15 @@
#include "DeviceCommandContext.h"
#include "ps/CLogger.h"
#include "renderer/backend/gl/Buffer.h"
#include "renderer/backend/gl/Device.h"
#include "renderer/backend/gl/Framebuffer.h"
#include "renderer/backend/gl/Mapping.h"
#include "renderer/backend/gl/Texture.h"
#include <algorithm>
#include <cstring>
#include <limits>
namespace Renderer
@ -87,6 +90,47 @@ void ApplyStencilMask(const uint32_t stencilWriteMask)
glStencilMask(stencilWriteMask);
}
GLenum BufferTypeToGLTarget(const CBuffer::Type type)
{
GLenum target = GL_ARRAY_BUFFER;
switch (type)
{
case CBuffer::Type::VERTEX:
target = GL_ARRAY_BUFFER;
break;
case CBuffer::Type::INDEX:
target = GL_ELEMENT_ARRAY_BUFFER;
break;
};
return target;
}
void UploadBufferRegionImpl(
const GLenum target, const uint32_t dataOffset, const uint32_t dataSize,
const CDeviceCommandContext::UploadBufferFunction& uploadFunction)
{
ENSURE(dataOffset < dataSize);
while (true)
{
void* mappedData = glMapBufferARB(target, GL_WRITE_ONLY);
if (mappedData == nullptr)
{
// This shouldn't happen unless we run out of virtual address space
LOGERROR("glMapBuffer failed");
break;
}
uploadFunction(static_cast<u8*>(mappedData) + dataOffset);
if (glUnmapBufferARB(target) == GL_TRUE)
break;
// Unmap might fail on e.g. resolution switches, so just try again
// and hope it will eventually succeed
LOGMESSAGE("glUnmapBuffer failed, trying again...\n");
}
}
} // anonymous namespace
// static
@ -240,6 +284,58 @@ void CDeviceCommandContext::UploadTextureRegion(
debug_warn("Unsupported type");
}
void CDeviceCommandContext::UploadBuffer(CBuffer* buffer, const void* data, const uint32_t dataSize)
{
UploadBufferRegion(buffer, data, dataSize, 0);
}
void CDeviceCommandContext::UploadBuffer(
CBuffer* buffer, const UploadBufferFunction& uploadFunction)
{
UploadBufferRegion(buffer, 0, buffer->GetSize(), uploadFunction);
}
void CDeviceCommandContext::UploadBufferRegion(
CBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize)
{
ENSURE(data);
ENSURE(dataOffset + dataSize <= buffer->GetSize());
const GLenum target = BufferTypeToGLTarget(buffer->GetType());
glBindBufferARB(target, buffer->GetHandle());
if (buffer->IsDynamic())
{
// Tell the driver that it can reallocate the whole VBO
glBufferDataARB(target, buffer->GetSize(), nullptr, buffer->IsDynamic() ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
// (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used
// here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with
// current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do
// the explicit glBufferData.)
UploadBufferRegion(buffer, dataOffset, dataSize, [data, dataOffset, dataSize](u8* mappedData)
{
std::memcpy(mappedData, data, dataSize);
});
}
else
{
glBufferSubDataARB(target, dataOffset, dataSize, data);
}
glBindBufferARB(target, 0);
}
void CDeviceCommandContext::UploadBufferRegion(
CBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize,
const UploadBufferFunction& uploadFunction)
{
ENSURE(dataOffset + dataSize <= buffer->GetSize());
const GLenum target = BufferTypeToGLTarget(buffer->GetType());
glBindBufferARB(target, buffer->GetHandle());
ENSURE(buffer->IsDynamic());
UploadBufferRegionImpl(target, dataOffset, dataSize, uploadFunction);
glBindBufferARB(target, 0);
}
void CDeviceCommandContext::BindTexture(const uint32_t unit, const GLenum target, const GLuint handle)
{
ENSURE(unit < m_BoundTextures.size());
@ -262,6 +358,12 @@ void CDeviceCommandContext::BindTexture(const uint32_t unit, const GLenum target
m_BoundTextures[unit] = {target, handle};
}
void CDeviceCommandContext::BindBuffer(const CBuffer::Type type, CBuffer* buffer)
{
ENSURE(!buffer || type == buffer->GetType());
glBindBufferARB(BufferTypeToGLTarget(type), buffer ? buffer->GetHandle() : 0);
}
void CDeviceCommandContext::Flush()
{
ResetStates();

View File

@ -20,10 +20,12 @@
#include "lib/ogl.h"
#include "renderer/backend/Format.h"
#include "renderer/backend/gl/Buffer.h"
#include "renderer/backend/PipelineState.h"
#include <array>
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <utility>
@ -65,6 +67,15 @@ public:
const uint32_t width, const uint32_t height,
const uint32_t level = 0, const uint32_t layer = 0);
using UploadBufferFunction = std::function<void(u8*)>;
void UploadBuffer(CBuffer* buffer, const void* data, const uint32_t dataSize);
void UploadBuffer(CBuffer* buffer, const UploadBufferFunction& uploadFunction);
void UploadBufferRegion(
CBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize);
void UploadBufferRegion(
CBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize,
const UploadBufferFunction& uploadFunction);
// TODO: maybe we should add a more common type, like CRectI.
struct ScissorRect
{
@ -75,6 +86,7 @@ public:
// TODO: remove direct binding after moving shaders.
void BindTexture(const uint32_t unit, const GLenum target, const GLuint handle);
void BindBuffer(const CBuffer::Type type, CBuffer* buffer);
void Flush();