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:
parent
6a2a297c0e
commit
cff79b421a
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
73
source/renderer/backend/gl/Buffer.cpp
Normal file
73
source/renderer/backend/gl/Buffer.cpp
Normal 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
|
76
source/renderer/backend/gl/Buffer.h
Normal file
76
source/renderer/backend/gl/Buffer.h
Normal 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
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user