mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-09-21 20:06:40 +00:00
Optimise vertex skinning code with SSE, based on patch by gruby.
Fixes #905. This was SVN commit r10499.
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
#include "ObjectEntry.h"
|
#include "ObjectEntry.h"
|
||||||
#include "lib/res/graphics/ogl_tex.h"
|
#include "lib/res/graphics/ogl_tex.h"
|
||||||
#include "lib/res/h_mgr.h"
|
#include "lib/res/h_mgr.h"
|
||||||
|
#include "lib/sysdep/rtl.h"
|
||||||
#include "ps/Profile.h"
|
#include "ps/Profile.h"
|
||||||
|
|
||||||
#include "ps/CLogger.h"
|
#include "ps/CLogger.h"
|
||||||
@@ -57,7 +58,7 @@ CModel::~CModel()
|
|||||||
// ReleaseData: delete anything allocated by the model
|
// ReleaseData: delete anything allocated by the model
|
||||||
void CModel::ReleaseData()
|
void CModel::ReleaseData()
|
||||||
{
|
{
|
||||||
delete[] m_BoneMatrices;
|
rtl_FreeAligned(m_BoneMatrices);
|
||||||
delete[] m_InverseBindBoneMatrices;
|
delete[] m_InverseBindBoneMatrices;
|
||||||
|
|
||||||
for (size_t i = 0; i < m_Props.size(); ++i)
|
for (size_t i = 0; i < m_Props.size(); ++i)
|
||||||
@@ -84,7 +85,7 @@ bool CModel::InitModel(const CModelDefPtr& modeldef)
|
|||||||
size_t numBlends = modeldef->GetNumBlends();
|
size_t numBlends = modeldef->GetNumBlends();
|
||||||
|
|
||||||
// allocate matrices for bone transformations
|
// allocate matrices for bone transformations
|
||||||
m_BoneMatrices = new CMatrix3D[numBones + numBlends];
|
m_BoneMatrices = (CMatrix3D*)rtl_AllocateAligned(sizeof(CMatrix3D) * (numBones + numBlends), 16);
|
||||||
for (size_t i = 0; i < numBones + numBlends; ++i)
|
for (size_t i = 0; i < numBones + numBlends; ++i)
|
||||||
{
|
{
|
||||||
m_BoneMatrices[i].SetIdentity();
|
m_BoneMatrices[i].SetIdentity();
|
||||||
|
|||||||
@@ -154,11 +154,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool IsSkinned() { return (m_BoneMatrices != NULL); }
|
bool IsSkinned() { return (m_BoneMatrices != NULL); }
|
||||||
|
|
||||||
// return the models bone matrices
|
// return the models bone matrices; 16-byte aligned for SSE reads
|
||||||
const CMatrix3D* GetAnimatedBoneMatrices() {
|
const CMatrix3D* GetAnimatedBoneMatrices() {
|
||||||
ENSURE(m_PositionValid);
|
ENSURE(m_PositionValid);
|
||||||
return m_BoneMatrices;
|
return m_BoneMatrices;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CMatrix3D* GetInverseBindBoneMatrices() {
|
const CMatrix3D* GetInverseBindBoneMatrices() {
|
||||||
return m_InverseBindBoneMatrices;
|
return m_InverseBindBoneMatrices;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2010 Wildfire Games.
|
/* Copyright (C) 2011 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@@ -26,6 +26,10 @@
|
|||||||
#include "ps/FileIo.h"
|
#include "ps/FileIo.h"
|
||||||
#include "maths/Vector4D.h"
|
#include "maths/Vector4D.h"
|
||||||
|
|
||||||
|
#if ARCH_X86_X64
|
||||||
|
# include <xmmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
CVector3D CModelDef::SkinPoint(const SModelVertex& vtx,
|
CVector3D CModelDef::SkinPoint(const SModelVertex& vtx,
|
||||||
const CMatrix3D newPoseMatrices[])
|
const CMatrix3D newPoseMatrices[])
|
||||||
{
|
{
|
||||||
@@ -91,12 +95,18 @@ void CModelDef::SkinPointsAndNormals(
|
|||||||
const size_t* blendIndices,
|
const size_t* blendIndices,
|
||||||
const CMatrix3D newPoseMatrices[])
|
const CMatrix3D newPoseMatrices[])
|
||||||
{
|
{
|
||||||
|
// To avoid some performance overhead, get the raw vertex array pointers
|
||||||
|
char* PositionData = Position.GetData();
|
||||||
|
size_t PositionStride = Position.GetStride();
|
||||||
|
char* NormalData = Normal.GetData();
|
||||||
|
size_t NormalStride = Normal.GetStride();
|
||||||
|
|
||||||
for (size_t j = 0; j < numVertices; ++j)
|
for (size_t j = 0; j < numVertices; ++j)
|
||||||
{
|
{
|
||||||
const SModelVertex& vtx = vertices[j];
|
const SModelVertex& vtx = vertices[j];
|
||||||
|
|
||||||
Position[j] = newPoseMatrices[blendIndices[j]].Transform(vtx.m_Coords);
|
CVector3D pos = newPoseMatrices[blendIndices[j]].Transform(vtx.m_Coords);
|
||||||
Normal[j] = newPoseMatrices[blendIndices[j]].Rotate(vtx.m_Norm);
|
CVector3D norm = newPoseMatrices[blendIndices[j]].Rotate(vtx.m_Norm);
|
||||||
|
|
||||||
// If there was more than one influence, the result is probably not going
|
// If there was more than one influence, the result is probably not going
|
||||||
// to be of unit length (since it's a weighted sum of several independent
|
// to be of unit length (since it's a weighted sum of several independent
|
||||||
@@ -104,10 +114,95 @@ void CModelDef::SkinPointsAndNormals(
|
|||||||
// (It's fairly common to only have one influence, so it seems sensible to
|
// (It's fairly common to only have one influence, so it seems sensible to
|
||||||
// optimise that case a bit.)
|
// optimise that case a bit.)
|
||||||
if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence
|
if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence
|
||||||
Normal[j].Normalize();
|
norm.Normalize();
|
||||||
|
|
||||||
|
memcpy(PositionData + PositionStride*j, &pos.X, 3*sizeof(float));
|
||||||
|
memcpy(NormalData + NormalStride*j, &norm.X, 3*sizeof(float));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ARCH_X86_X64
|
||||||
|
void CModelDef::SkinPointsAndNormals_SSE(
|
||||||
|
size_t numVertices,
|
||||||
|
const VertexArrayIterator<CVector3D>& Position,
|
||||||
|
const VertexArrayIterator<CVector3D>& Normal,
|
||||||
|
const SModelVertex* vertices,
|
||||||
|
const size_t* blendIndices,
|
||||||
|
const CMatrix3D newPoseMatrices[])
|
||||||
|
{
|
||||||
|
// To avoid some performance overhead, get the raw vertex array pointers
|
||||||
|
char* PositionData = Position.GetData();
|
||||||
|
size_t PositionStride = Position.GetStride();
|
||||||
|
char* NormalData = Normal.GetData();
|
||||||
|
size_t NormalStride = Normal.GetStride();
|
||||||
|
|
||||||
|
// Must be aligned correctly for SSE
|
||||||
|
ASSERT((intptr_t)newPoseMatrices % 16 == 0);
|
||||||
|
ASSERT((intptr_t)PositionData % 16 == 0);
|
||||||
|
ASSERT((intptr_t)PositionStride % 16 == 0);
|
||||||
|
ASSERT((intptr_t)NormalData % 16 == 0);
|
||||||
|
ASSERT((intptr_t)NormalStride % 16 == 0);
|
||||||
|
|
||||||
|
__m128 col0, col1, col2, col3, vec0, vec1, vec2;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < numVertices; ++j)
|
||||||
|
{
|
||||||
|
const SModelVertex& vtx = vertices[j];
|
||||||
|
const CMatrix3D& mtx = newPoseMatrices[blendIndices[j]];
|
||||||
|
|
||||||
|
// Loads matrix to xmm registers.
|
||||||
|
col0 = _mm_load_ps(mtx._data);
|
||||||
|
col1 = _mm_load_ps(mtx._data + 4);
|
||||||
|
col2 = _mm_load_ps(mtx._data + 8);
|
||||||
|
col3 = _mm_load_ps(mtx._data + 12);
|
||||||
|
|
||||||
|
// Loads and computes vertex coordinates.
|
||||||
|
vec0 = _mm_load1_ps(&vtx.m_Coords.X);
|
||||||
|
vec0 = _mm_mul_ps(col0, vec0);
|
||||||
|
vec1 = _mm_load1_ps(&vtx.m_Coords.Y);
|
||||||
|
vec1 = _mm_mul_ps(col1, vec1);
|
||||||
|
vec0 = _mm_add_ps(vec0, vec1);
|
||||||
|
vec1 = _mm_load1_ps(&vtx.m_Coords.Z);
|
||||||
|
vec1 = _mm_mul_ps(col2, vec1);
|
||||||
|
vec1 = _mm_add_ps(vec1, col3);
|
||||||
|
vec0 = _mm_add_ps(vec0, vec1);
|
||||||
|
_mm_store_ps((float*)(PositionData + PositionStride*j), vec0);
|
||||||
|
|
||||||
|
// Loads and computes normal vectors.
|
||||||
|
vec0 = _mm_load1_ps(&vtx.m_Norm.X);
|
||||||
|
vec0 = _mm_mul_ps(col0, vec0);
|
||||||
|
vec1 = _mm_load1_ps(&vtx.m_Norm.Y);
|
||||||
|
vec1 = _mm_mul_ps(col1, vec1);
|
||||||
|
vec0 = _mm_add_ps(vec0, vec1);
|
||||||
|
vec1 = _mm_load1_ps(&vtx.m_Norm.Z);
|
||||||
|
vec1 = _mm_mul_ps(col2, vec1);
|
||||||
|
vec0 = _mm_add_ps(vec0, vec1);
|
||||||
|
|
||||||
|
// If there was more than one influence, the result is probably not going
|
||||||
|
// to be of unit length (since it's a weighted sum of several independent
|
||||||
|
// unit vectors), so we need to normalise it.
|
||||||
|
// (It's fairly common to only have one influence, so it seems sensible to
|
||||||
|
// optimise that case a bit.)
|
||||||
|
if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence
|
||||||
|
{
|
||||||
|
// Normalization.
|
||||||
|
// vec1 = [x*x, y*y, z*z, ?*?]
|
||||||
|
vec1 = _mm_mul_ps(vec0, vec0);
|
||||||
|
// vec2 = [y*y, z*z, x*x, y*y]
|
||||||
|
vec2 = _mm_shuffle_ps(vec1, vec1, _MM_SHUFFLE(1, 2, 0, 1));
|
||||||
|
vec1 = _mm_add_ps(vec1, vec2);
|
||||||
|
// vec2 = [z*z, x*x, y*y, z*z]
|
||||||
|
vec2 = _mm_shuffle_ps(vec2, vec2, _MM_SHUFFLE(1, 2, 0, 1));
|
||||||
|
vec1 = _mm_add_ps(vec1, vec2);
|
||||||
|
// rsqrt(a) = 1 / sqrt(a)
|
||||||
|
vec1 = _mm_rsqrt_ps(vec1);
|
||||||
|
vec0 = _mm_mul_ps(vec0, vec1);
|
||||||
|
}
|
||||||
|
_mm_store_ps((float*)(NormalData + NormalStride*j), vec0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void CModelDef::BlendBoneMatrices(
|
void CModelDef::BlendBoneMatrices(
|
||||||
CMatrix3D boneMatrices[])
|
CMatrix3D boneMatrices[])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2010 Wildfire Games.
|
/* Copyright (C) 2011 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@@ -179,6 +179,19 @@ public:
|
|||||||
const size_t* blendIndices,
|
const size_t* blendIndices,
|
||||||
const CMatrix3D newPoseMatrices[]);
|
const CMatrix3D newPoseMatrices[]);
|
||||||
|
|
||||||
|
#if ARCH_X86_X64
|
||||||
|
/**
|
||||||
|
* SSE-optimised version of SkinPointsAndNormals.
|
||||||
|
*/
|
||||||
|
static void SkinPointsAndNormals_SSE(
|
||||||
|
size_t numVertices,
|
||||||
|
const VertexArrayIterator<CVector3D>& Position,
|
||||||
|
const VertexArrayIterator<CVector3D>& Normal,
|
||||||
|
const SModelVertex* vertices,
|
||||||
|
const size_t* blendIndices,
|
||||||
|
const CMatrix3D newPoseMatrices[]);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blend bone matrices together to fill bone palette.
|
* Blend bone matrices together to fill bone palette.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
|
|
||||||
#include "renderer/Renderer.h"
|
#include "renderer/Renderer.h"
|
||||||
#include "renderer/VertexBufferManager.h"
|
#include "renderer/VertexBufferManager.h"
|
||||||
|
#include "renderer/ModelRenderer.h"
|
||||||
|
|
||||||
#include "maths/MathUtil.h"
|
#include "maths/MathUtil.h"
|
||||||
|
|
||||||
@@ -591,6 +592,7 @@ static void InitRenderer()
|
|||||||
g_Renderer.SetViewport(vp);
|
g_Renderer.SetViewport(vp);
|
||||||
|
|
||||||
ColorActivateFastImpl();
|
ColorActivateFastImpl();
|
||||||
|
ModelRenderer::Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitSDL()
|
static void InitSDL()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
/* Copyright (C) 2011 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@@ -21,7 +21,9 @@
|
|||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
#include "lib/bits.h"
|
||||||
#include "lib/ogl.h"
|
#include "lib/ogl.h"
|
||||||
|
#include "lib/sysdep/rtl.h"
|
||||||
#include "maths/Vector3D.h"
|
#include "maths/Vector3D.h"
|
||||||
#include "maths/Vector4D.h"
|
#include "maths/Vector4D.h"
|
||||||
|
|
||||||
@@ -97,8 +99,13 @@ struct FFModel
|
|||||||
|
|
||||||
struct FixedFunctionModelRendererInternals
|
struct FixedFunctionModelRendererInternals
|
||||||
{
|
{
|
||||||
/// Transformed vertex normals - required for recalculating lighting on skinned models
|
/**
|
||||||
std::vector<CVector3D> normals;
|
* Scratch space for normal vector calculation.
|
||||||
|
* Space is reserved so we don't have to do frequent reallocations.
|
||||||
|
* Allocated with rtl_AllocateAligned(normalsNumVertices*16, 16) for SSE writes.
|
||||||
|
*/
|
||||||
|
char* normals;
|
||||||
|
size_t normalsNumVertices;
|
||||||
|
|
||||||
/// Previously prepared modeldef
|
/// Previously prepared modeldef
|
||||||
FFModelDef* ffmodeldef;
|
FFModelDef* ffmodeldef;
|
||||||
@@ -110,10 +117,14 @@ FixedFunctionModelRenderer::FixedFunctionModelRenderer()
|
|||||||
{
|
{
|
||||||
m = new FixedFunctionModelRendererInternals;
|
m = new FixedFunctionModelRendererInternals;
|
||||||
m->ffmodeldef = 0;
|
m->ffmodeldef = 0;
|
||||||
|
m->normals = 0;
|
||||||
|
m->normalsNumVertices = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedFunctionModelRenderer::~FixedFunctionModelRenderer()
|
FixedFunctionModelRenderer::~FixedFunctionModelRenderer()
|
||||||
{
|
{
|
||||||
|
rtl_FreeAligned(m->normals);
|
||||||
|
|
||||||
delete m;
|
delete m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,17 +144,26 @@ void* FixedFunctionModelRenderer::CreateModelData(CModel* model)
|
|||||||
// Build the per-model data
|
// Build the per-model data
|
||||||
FFModel* ffmodel = new FFModel;
|
FFModel* ffmodel = new FFModel;
|
||||||
|
|
||||||
ffmodel->m_Position.type = GL_FLOAT;
|
// Positions must be 16-byte aligned for SSE writes.
|
||||||
ffmodel->m_Position.elems = 3;
|
// We can pack the color after the position; it will be corrupted by
|
||||||
ffmodel->m_Array.AddAttribute(&ffmodel->m_Position);
|
// BuildPositionAndNormals, but that's okay since we'll recompute the
|
||||||
|
// colors afterwards.
|
||||||
|
|
||||||
ffmodel->m_Color.type = GL_UNSIGNED_BYTE;
|
ffmodel->m_Color.type = GL_UNSIGNED_BYTE;
|
||||||
ffmodel->m_Color.elems = 4;
|
ffmodel->m_Color.elems = 4;
|
||||||
ffmodel->m_Array.AddAttribute(&ffmodel->m_Color);
|
ffmodel->m_Array.AddAttribute(&ffmodel->m_Color);
|
||||||
|
|
||||||
|
ffmodel->m_Position.type = GL_FLOAT;
|
||||||
|
ffmodel->m_Position.elems = 3;
|
||||||
|
ffmodel->m_Array.AddAttribute(&ffmodel->m_Position);
|
||||||
|
|
||||||
ffmodel->m_Array.SetNumVertices(mdef->GetNumVertices());
|
ffmodel->m_Array.SetNumVertices(mdef->GetNumVertices());
|
||||||
ffmodel->m_Array.Layout();
|
ffmodel->m_Array.Layout();
|
||||||
|
|
||||||
|
// Verify alignment
|
||||||
|
ENSURE(ffmodel->m_Position.offset % 16 == 0);
|
||||||
|
ENSURE(ffmodel->m_Array.GetStride() % 16 == 0);
|
||||||
|
|
||||||
return ffmodel;
|
return ffmodel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,11 +179,19 @@ void FixedFunctionModelRenderer::UpdateModelData(CModel* model, void* data, int
|
|||||||
size_t numVertices = mdef->GetNumVertices();
|
size_t numVertices = mdef->GetNumVertices();
|
||||||
|
|
||||||
// build vertices
|
// build vertices
|
||||||
if (m->normals.size() < numVertices)
|
|
||||||
m->normals.resize(numVertices);
|
// allocate working space for computing normals
|
||||||
|
if (numVertices > m->normalsNumVertices)
|
||||||
|
{
|
||||||
|
rtl_FreeAligned(m->normals);
|
||||||
|
|
||||||
|
size_t newSize = round_up_to_pow2(numVertices);
|
||||||
|
m->normals = (char*)rtl_AllocateAligned(newSize*16, 16);
|
||||||
|
m->normalsNumVertices = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
VertexArrayIterator<CVector3D> Position = ffmodel->m_Position.GetIterator<CVector3D>();
|
VertexArrayIterator<CVector3D> Position = ffmodel->m_Position.GetIterator<CVector3D>();
|
||||||
VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>((char*)&m->normals[0], sizeof(CVector3D));
|
VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>(m->normals, 16);
|
||||||
|
|
||||||
ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
|
ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
|
||||||
|
|
||||||
|
|||||||
@@ -37,13 +37,35 @@ struct ShaderModelDef : public CModelDefRPrivate
|
|||||||
/// Indices are the same for all models, so share them
|
/// Indices are the same for all models, so share them
|
||||||
VertexIndexArray m_IndexArray;
|
VertexIndexArray m_IndexArray;
|
||||||
|
|
||||||
|
/// Static per-CModelDef vertex array
|
||||||
|
VertexArray m_Array;
|
||||||
|
|
||||||
|
/// UV coordinates are stored in the static array
|
||||||
|
VertexArray::Attribute m_UV;
|
||||||
|
|
||||||
ShaderModelDef(const CModelDefPtr& mdef);
|
ShaderModelDef(const CModelDefPtr& mdef);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef)
|
ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef)
|
||||||
: m_IndexArray(GL_STATIC_DRAW)
|
: m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
|
||||||
{
|
{
|
||||||
|
size_t numVertices = mdef->GetNumVertices();
|
||||||
|
|
||||||
|
m_UV.type = GL_FLOAT;
|
||||||
|
m_UV.elems = 2;
|
||||||
|
m_Array.AddAttribute(&m_UV);
|
||||||
|
|
||||||
|
m_Array.SetNumVertices(numVertices);
|
||||||
|
m_Array.Layout();
|
||||||
|
|
||||||
|
VertexArrayIterator<float[2]> UVit = m_UV.GetIterator<float[2]>();
|
||||||
|
|
||||||
|
ModelRenderer::BuildUV(mdef, UVit);
|
||||||
|
|
||||||
|
m_Array.Upload();
|
||||||
|
m_Array.FreeBackingStore();
|
||||||
|
|
||||||
m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
|
m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
|
||||||
m_IndexArray.Layout();
|
m_IndexArray.Layout();
|
||||||
ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
|
ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
|
||||||
@@ -61,9 +83,6 @@ struct ShaderModel
|
|||||||
VertexArray::Attribute m_Position;
|
VertexArray::Attribute m_Position;
|
||||||
VertexArray::Attribute m_Normal;
|
VertexArray::Attribute m_Normal;
|
||||||
|
|
||||||
/// UV is stored per-CModel in order to avoid space wastage due to alignment
|
|
||||||
VertexArray::Attribute m_UV;
|
|
||||||
|
|
||||||
ShaderModel() : m_Array(GL_DYNAMIC_DRAW) { }
|
ShaderModel() : m_Array(GL_DYNAMIC_DRAW) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,25 +122,23 @@ void* ShaderModelRenderer::CreateModelData(CModel* model)
|
|||||||
// Build the per-model data
|
// Build the per-model data
|
||||||
ShaderModel* shadermodel = new ShaderModel;
|
ShaderModel* shadermodel = new ShaderModel;
|
||||||
|
|
||||||
|
// Positions and normals must be 16-byte aligned for SSE writes.
|
||||||
|
|
||||||
shadermodel->m_Position.type = GL_FLOAT;
|
shadermodel->m_Position.type = GL_FLOAT;
|
||||||
shadermodel->m_Position.elems = 3;
|
shadermodel->m_Position.elems = 4;
|
||||||
shadermodel->m_Array.AddAttribute(&shadermodel->m_Position);
|
shadermodel->m_Array.AddAttribute(&shadermodel->m_Position);
|
||||||
|
|
||||||
shadermodel->m_UV.type = GL_FLOAT;
|
|
||||||
shadermodel->m_UV.elems = 2;
|
|
||||||
shadermodel->m_Array.AddAttribute(&shadermodel->m_UV);
|
|
||||||
|
|
||||||
shadermodel->m_Normal.type = GL_FLOAT;
|
shadermodel->m_Normal.type = GL_FLOAT;
|
||||||
shadermodel->m_Normal.elems = 3;
|
shadermodel->m_Normal.elems = 4;
|
||||||
shadermodel->m_Array.AddAttribute(&shadermodel->m_Normal);
|
shadermodel->m_Array.AddAttribute(&shadermodel->m_Normal);
|
||||||
|
|
||||||
shadermodel->m_Array.SetNumVertices(mdef->GetNumVertices());
|
shadermodel->m_Array.SetNumVertices(mdef->GetNumVertices());
|
||||||
shadermodel->m_Array.Layout();
|
shadermodel->m_Array.Layout();
|
||||||
|
|
||||||
// Fill in static UV coordinates
|
// Verify alignment
|
||||||
VertexArrayIterator<float[2]> UVit = shadermodel->m_UV.GetIterator<float[2]>();
|
ENSURE(shadermodel->m_Position.offset % 16 == 0);
|
||||||
|
ENSURE(shadermodel->m_Normal.offset % 16 == 0);
|
||||||
ModelRenderer::BuildUV(mdef, UVit);
|
ENSURE(shadermodel->m_Array.GetStride() % 16 == 0);
|
||||||
|
|
||||||
return shadermodel;
|
return shadermodel;
|
||||||
}
|
}
|
||||||
@@ -188,11 +205,19 @@ void ShaderModelRenderer::EndPass(int streamflags)
|
|||||||
|
|
||||||
|
|
||||||
// Prepare UV coordinates for this modeldef
|
// Prepare UV coordinates for this modeldef
|
||||||
void ShaderModelRenderer::PrepareModelDef(int UNUSED(streamflags), const CModelDefPtr& def)
|
void ShaderModelRenderer::PrepareModelDef(int streamflags, const CModelDefPtr& def)
|
||||||
{
|
{
|
||||||
m->shadermodeldef = (ShaderModelDef*)def->GetRenderData(m);
|
m->shadermodeldef = (ShaderModelDef*)def->GetRenderData(m);
|
||||||
|
|
||||||
ENSURE(m->shadermodeldef);
|
ENSURE(m->shadermodeldef);
|
||||||
|
|
||||||
|
if (streamflags & STREAM_UV0)
|
||||||
|
{
|
||||||
|
u8* base = m->shadermodeldef->m_Array.Bind();
|
||||||
|
GLsizei stride = (GLsizei)m->shadermodeldef->m_Array.GetStride();
|
||||||
|
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, stride, base + m->shadermodeldef->m_UV.offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -213,9 +238,6 @@ void ShaderModelRenderer::RenderModel(int streamflags, CModel* model, void* data
|
|||||||
if (streamflags & STREAM_NORMAL)
|
if (streamflags & STREAM_NORMAL)
|
||||||
glNormalPointer(GL_FLOAT, stride, base + shadermodel->m_Normal.offset);
|
glNormalPointer(GL_FLOAT, stride, base + shadermodel->m_Normal.offset);
|
||||||
|
|
||||||
if (streamflags & STREAM_UV0)
|
|
||||||
glTexCoordPointer(2, GL_FLOAT, stride, base + shadermodel->m_UV.offset);
|
|
||||||
|
|
||||||
// render the lot
|
// render the lot
|
||||||
size_t numFaces = mdldef->GetNumFaces();
|
size_t numFaces = mdldef->GetNumFaces();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
/* Copyright (C) 2011 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@@ -41,10 +41,23 @@
|
|||||||
|
|
||||||
#include <boost/weak_ptr.hpp>
|
#include <boost/weak_ptr.hpp>
|
||||||
|
|
||||||
|
#if ARCH_X86_X64
|
||||||
|
# include "lib/sysdep/arch/x86_x64/x86_x64.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// ModelRenderer implementation
|
// ModelRenderer implementation
|
||||||
|
|
||||||
|
static bool g_EnableSSE = false;
|
||||||
|
|
||||||
|
void ModelRenderer::Init()
|
||||||
|
{
|
||||||
|
#if ARCH_X86_X64
|
||||||
|
if (x86_x64_cap(X86_X64_CAP_SSE))
|
||||||
|
g_EnableSSE = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to copy object-space position and normal vectors into arrays.
|
// Helper function to copy object-space position and normal vectors into arrays.
|
||||||
void ModelRenderer::CopyPositionAndNormals(
|
void ModelRenderer::CopyPositionAndNormals(
|
||||||
const CModelDefPtr& mdef,
|
const CModelDefPtr& mdef,
|
||||||
@@ -84,8 +97,10 @@ void ModelRenderer::BuildPositionAndNormals(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CModelDef::SkinPointsAndNormals(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices());
|
if (g_EnableSSE)
|
||||||
|
CModelDef::SkinPointsAndNormals_SSE(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices());
|
||||||
|
else
|
||||||
|
CModelDef::SkinPointsAndNormals(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
/* Copyright (C) 2011 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@@ -123,6 +123,12 @@ public:
|
|||||||
ModelRenderer() { }
|
ModelRenderer() { }
|
||||||
virtual ~ModelRenderer() { }
|
virtual ~ModelRenderer() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise global settings.
|
||||||
|
* Should be called before using the class.
|
||||||
|
*/
|
||||||
|
static void Init();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit: Submit a model for rendering this frame.
|
* Submit: Submit a model for rendering this frame.
|
||||||
*
|
*
|
||||||
@@ -212,7 +218,8 @@ public:
|
|||||||
* @param Position Points to the array that will receive
|
* @param Position Points to the array that will receive
|
||||||
* transformed position vectors. The array behind the iterator
|
* transformed position vectors. The array behind the iterator
|
||||||
* must be large enough to hold model->GetModelDef()->GetNumVertices()
|
* must be large enough to hold model->GetModelDef()->GetNumVertices()
|
||||||
* vertices.
|
* vertices. It must allow 16 bytes to be written to each element
|
||||||
|
* (i.e. provide 4 bytes of padding after each CVector3D).
|
||||||
* @param Normal Points to the array that will receive transformed
|
* @param Normal Points to the array that will receive transformed
|
||||||
* normal vectors. The array behind the iterator must be as large as
|
* normal vectors. The array behind the iterator must be as large as
|
||||||
* the Position array.
|
* the Position array.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
/* Copyright (C) 2011 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@@ -25,7 +25,9 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "lib/bits.h"
|
||||||
#include "lib/ogl.h"
|
#include "lib/ogl.h"
|
||||||
|
#include "lib/sysdep/rtl.h"
|
||||||
#include "maths/MathUtil.h"
|
#include "maths/MathUtil.h"
|
||||||
#include "maths/Vector3D.h"
|
#include "maths/Vector3D.h"
|
||||||
#include "maths/Vector4D.h"
|
#include "maths/Vector4D.h"
|
||||||
@@ -117,17 +119,26 @@ PSModel::PSModel(CModel* model)
|
|||||||
{
|
{
|
||||||
CModelDefPtr mdef = m_Model->GetModelDef();
|
CModelDefPtr mdef = m_Model->GetModelDef();
|
||||||
|
|
||||||
m_Position.type = GL_FLOAT;
|
// Positions and normals must be 16-byte aligned for SSE writes.
|
||||||
m_Position.elems = 3;
|
// We can pack the color after the position; it will be corrupted by
|
||||||
m_Array.AddAttribute(&m_Position);
|
// BuildPositionAndNormals, but that's okay since we'll recompute the
|
||||||
|
// colors afterwards.
|
||||||
|
|
||||||
m_Color.type = GL_UNSIGNED_BYTE;
|
m_Color.type = GL_UNSIGNED_BYTE;
|
||||||
m_Color.elems = 4;
|
m_Color.elems = 4;
|
||||||
m_Array.AddAttribute(&m_Color);
|
m_Array.AddAttribute(&m_Color);
|
||||||
|
|
||||||
|
m_Position.type = GL_FLOAT;
|
||||||
|
m_Position.elems = 3;
|
||||||
|
m_Array.AddAttribute(&m_Position);
|
||||||
|
|
||||||
m_Array.SetNumVertices(mdef->GetNumVertices());
|
m_Array.SetNumVertices(mdef->GetNumVertices());
|
||||||
m_Array.Layout();
|
m_Array.Layout();
|
||||||
|
|
||||||
|
// Verify alignment
|
||||||
|
ENSURE(m_Position.offset % 16 == 0);
|
||||||
|
ENSURE(m_Array.GetStride() % 16 == 0);
|
||||||
|
|
||||||
m_Indices = new u16[mdef->GetNumFaces()*3];
|
m_Indices = new u16[mdef->GetNumFaces()*3];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,8 +205,13 @@ float PSModel::BackToFrontIndexSort(const CMatrix3D& worldToCam)
|
|||||||
*/
|
*/
|
||||||
struct PolygonSortModelRendererInternals
|
struct PolygonSortModelRendererInternals
|
||||||
{
|
{
|
||||||
/// Scratch space for normal vector calculation
|
/**
|
||||||
std::vector<CVector3D> normals;
|
* Scratch space for normal vector calculation.
|
||||||
|
* Space is reserved so we don't have to do frequent reallocations.
|
||||||
|
* Allocated with rtl_AllocateAligned(normalsNumVertices*16, 16) for SSE writes.
|
||||||
|
*/
|
||||||
|
char* normals;
|
||||||
|
size_t normalsNumVertices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -203,10 +219,14 @@ struct PolygonSortModelRendererInternals
|
|||||||
PolygonSortModelRenderer::PolygonSortModelRenderer()
|
PolygonSortModelRenderer::PolygonSortModelRenderer()
|
||||||
{
|
{
|
||||||
m = new PolygonSortModelRendererInternals;
|
m = new PolygonSortModelRendererInternals;
|
||||||
|
m->normals = 0;
|
||||||
|
m->normalsNumVertices = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PolygonSortModelRenderer::~PolygonSortModelRenderer()
|
PolygonSortModelRenderer::~PolygonSortModelRenderer()
|
||||||
{
|
{
|
||||||
|
rtl_FreeAligned(m->normals);
|
||||||
|
|
||||||
delete m;
|
delete m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,11 +257,19 @@ void PolygonSortModelRenderer::UpdateModelData(CModel* model, void* data, int up
|
|||||||
size_t numVertices = mdef->GetNumVertices();
|
size_t numVertices = mdef->GetNumVertices();
|
||||||
|
|
||||||
// build vertices
|
// build vertices
|
||||||
if (m->normals.size() < numVertices)
|
|
||||||
m->normals.resize(numVertices);
|
// allocate working space for computing normals
|
||||||
|
if (numVertices > m->normalsNumVertices)
|
||||||
|
{
|
||||||
|
rtl_FreeAligned(m->normals);
|
||||||
|
|
||||||
|
size_t newSize = round_up_to_pow2(numVertices);
|
||||||
|
m->normals = (char*)rtl_AllocateAligned(newSize*16, 16);
|
||||||
|
m->normalsNumVertices = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
VertexArrayIterator<CVector3D> Position = psmdl->m_Position.GetIterator<CVector3D>();
|
VertexArrayIterator<CVector3D> Position = psmdl->m_Position.GetIterator<CVector3D>();
|
||||||
VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>((char*)&m->normals[0], sizeof(CVector3D));
|
VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>(m->normals, 16);
|
||||||
|
|
||||||
ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
|
ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "lib/alignment.h"
|
#include "lib/alignment.h"
|
||||||
#include "lib/ogl.h"
|
#include "lib/ogl.h"
|
||||||
|
#include "lib/sysdep/rtl.h"
|
||||||
#include "maths/Vector3D.h"
|
#include "maths/Vector3D.h"
|
||||||
#include "maths/Vector4D.h"
|
#include "maths/Vector4D.h"
|
||||||
#include "graphics/SColor.h"
|
#include "graphics/SColor.h"
|
||||||
@@ -47,7 +48,7 @@ VertexArray::~VertexArray()
|
|||||||
// Free all resources on destruction or when a layout parameter changes
|
// Free all resources on destruction or when a layout parameter changes
|
||||||
void VertexArray::Free()
|
void VertexArray::Free()
|
||||||
{
|
{
|
||||||
delete[] m_BackingStore;
|
rtl_FreeAligned(m_BackingStore);
|
||||||
m_BackingStore = 0;
|
m_BackingStore = 0;
|
||||||
|
|
||||||
if (m_VB)
|
if (m_VB)
|
||||||
@@ -214,7 +215,7 @@ void VertexArray::Layout()
|
|||||||
//debug_printf(L"Stride: %u\n", m_Stride);
|
//debug_printf(L"Stride: %u\n", m_Stride);
|
||||||
|
|
||||||
if (m_Stride)
|
if (m_Stride)
|
||||||
m_BackingStore = new char[m_Stride * m_NumVertices];
|
m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumVertices, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -249,7 +250,7 @@ u8* VertexArray::Bind()
|
|||||||
// Free the backing store to save some memory
|
// Free the backing store to save some memory
|
||||||
void VertexArray::FreeBackingStore()
|
void VertexArray::FreeBackingStore()
|
||||||
{
|
{
|
||||||
delete[] m_BackingStore;
|
rtl_FreeAligned(m_BackingStore);
|
||||||
m_BackingStore = 0;
|
m_BackingStore = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,16 @@ public:
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accessors for raw buffer data, for performance-critical code
|
||||||
|
char* GetData() const
|
||||||
|
{
|
||||||
|
return m_Data;
|
||||||
|
}
|
||||||
|
size_t GetStride() const
|
||||||
|
{
|
||||||
|
return m_Stride;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* m_Data;
|
char* m_Data;
|
||||||
size_t m_Stride;
|
size_t m_Stride;
|
||||||
@@ -187,7 +197,7 @@ private:
|
|||||||
|
|
||||||
CVertexBuffer::VBChunk* m_VB;
|
CVertexBuffer::VBChunk* m_VB;
|
||||||
size_t m_Stride;
|
size_t m_Stride;
|
||||||
char* m_BackingStore;
|
char* m_BackingStore; // 16-byte aligned, to allow fast SSE access
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user