From 6fc1f45fa61b8d1fc0d6985699f1354c77b55ccb Mon Sep 17 00:00:00 2001 From: prefect Date: Mon, 3 Oct 2005 03:41:42 +0000 Subject: [PATCH] Stab at fixing the VertexArray compile error on VC++. Added float-to-byte color conversion, including an SSE assembler version. Model renderer: Push UV coordinates into a shared vertex array and use bytes instead of floats for the color array, thereby, significantly reducing the total size of vertex arrays. This was SVN commit r2827. --- source/graphics/Color.cpp | 19 +++++++++ source/graphics/Color.h | 2 + source/lib/detect.cpp | 30 +++++++++++++- source/lib/sysdep/cpu.h | 2 +- source/lib/sysdep/ia32.asm | 49 ++++++++++++++++++++++ source/lib/sysdep/ia32.cpp | 21 +++++++++- source/lib/sysdep/ia32.h | 1 + source/ps/GameSetup/GameSetup.cpp | 22 ++-------- source/renderer/ModelDefRData.cpp | 36 ++++++++++++++++- source/renderer/ModelDefRData.h | 6 +++ source/renderer/ModelRData.cpp | 67 +++++++++++++++++++------------ source/renderer/VertexArray.cpp | 5 ++- 12 files changed, 210 insertions(+), 50 deletions(-) create mode 100644 source/graphics/Color.cpp diff --git a/source/graphics/Color.cpp b/source/graphics/Color.cpp new file mode 100644 index 0000000000..ce3ace90d1 --- /dev/null +++ b/source/graphics/Color.cpp @@ -0,0 +1,19 @@ +#include "precompiled.h" + +#include "MathUtil.h" +#include "graphics/Color.h" + + +static u32 fallback_ConvertRGBColorTo4ub(const RGBColor& src) +{ + SColor4ub result; + result.R=clamp(int(src.X*255),0,255); + result.G=clamp(int(src.Y*255),0,255); + result.B=clamp(int(src.Z*255),0,255); + result.A=0xff; + return *(u32*)&result; +} + +// on IA32, this is replaced by an SSE assembly version in ia32.cpp +u32 (*ConvertRGBColorTo4ub)(const RGBColor& src) = fallback_ConvertRGBColorTo4ub; + diff --git a/source/graphics/Color.h b/source/graphics/Color.h index 5d52e544df..1f7ebecd40 100755 --- a/source/graphics/Color.h +++ b/source/graphics/Color.h @@ -35,5 +35,7 @@ struct SColor4ub u8 A; }; +extern u32 (*ConvertRGBColorTo4ub)(const RGBColor& src); + #endif diff --git a/source/lib/detect.cpp b/source/lib/detect.cpp index 002825ece1..b8718647e1 100755 --- a/source/lib/detect.cpp +++ b/source/lib/detect.cpp @@ -128,7 +128,7 @@ int cpu_ht_units = -1; int cpu_cores = -1; int cpu_speedstep = -1; -void get_cpu_info() +static void get_cpu_info() { #if OS_WIN win_get_cpu_info(); @@ -142,6 +142,34 @@ void get_cpu_info() } +void cpu_init() +{ +#if CPU_IA32 + ia32_init(); +#endif + + // If you ever want to catch a particular allocation: + //_CrtSetBreakAlloc(187); + + // no longer set 24 bit (float) precision by default: for + // very long game uptimes (> 1 day; e.g. dedicated server), + // we need full precision when calculating the time. + // if there's a spot where we want to speed up divides|sqrts, + // we can temporarily change precision there. + // _control87(_PC_24, _MCW_PC); + + // detects CPU clock frequency and capabilities, which are prerequisites + // for using the TSC as a timer (desirable due to its high resolution). + // do this before lengthy init so we can time those accurately. + get_cpu_info(); + +#if CPU_IA32 + // If possible, hook up capability-sensitive assembler routines + ia32_hook_capabilities(); +#endif +} + + // // sound // diff --git a/source/lib/sysdep/cpu.h b/source/lib/sysdep/cpu.h index baf9b98b7c..46b9f76e17 100755 --- a/source/lib/sysdep/cpu.h +++ b/source/lib/sysdep/cpu.h @@ -21,7 +21,7 @@ extern int cpu_cores; // cores per package, typically 2 extern int cpu_speedstep; -extern void get_cpu_info(void); +extern void cpu_init(void); // atomic "compare and swap". compare the machine word at against diff --git a/source/lib/sysdep/ia32.asm b/source/lib/sysdep/ia32.asm index 801e04e9d4..7e878bfb9e 100644 --- a/source/lib/sysdep/ia32.asm +++ b/source/lib/sysdep/ia32.asm @@ -398,3 +398,52 @@ extern sym(ia32_cap) pop ebx ret + +;------------------------------------------------------------------------------- +; Color conversion (SSE) +;------------------------------------------------------------------------------- + +; extern "C" u32 ConvertRGBColorTo4ub(const RGBColor& color) +[section .data] + align 16 +zero: + dd 0.0 +twofivefive: + dd 255.0 + + +__SECT__ + align 16 +global sym(sse_ConvertRGBColorTo4ub) +sym(sse_ConvertRGBColorTo4ub): + mov eax, [esp+4] + + ; xmm0, 1, 2 = R, G, B + movss xmm4, [zero] + movss xmm0, [eax+8] + movss xmm1, [eax+4] + movss xmm2, [eax] + movss xmm5, [twofivefive] + + ; C = min(255, 255*max(C, 0)) ( == clamp(255*C, 0, 255) ) + maxss xmm0, xmm4 + maxss xmm1, xmm4 + maxss xmm2, xmm4 + mulss xmm0, xmm5 + mulss xmm1, xmm5 + mulss xmm2, xmm5 + minss xmm0, xmm5 + minss xmm1, xmm5 + minss xmm2, xmm5 + + ; convert to integer and combine channels using bit logic + cvtss2si eax, xmm0 + cvtss2si ecx, xmm1 + cvtss2si edx, xmm2 + shl eax, 16 + shl ecx, 8 + or eax, 0xff000000 + or edx, ecx + or eax, edx + + ret diff --git a/source/lib/sysdep/ia32.cpp b/source/lib/sysdep/ia32.cpp index a3e8f46800..6f84e034fa 100755 --- a/source/lib/sysdep/ia32.cpp +++ b/source/lib/sysdep/ia32.cpp @@ -28,6 +28,7 @@ #include "win/wtime.h" #endif +#include "graphics/Color.h" #include #include @@ -525,7 +526,7 @@ static void measure_cpu_freq() u64 c1; double t1; do { - // note: get_time effectively has a long delay (up to 5 µs) + // note: get_time effectively has a long delay (up to 5 s) // before returning the time. we call it before rdtsc to // minimize the delay between actually sampling time / TSC, // thus decreasing the chance for interference. @@ -588,3 +589,21 @@ void ia32_get_cpu_info() wtime_reset_impl(); #endif } + + +// Assembler-optimized function for color conversion +extern "C" { +u32 sse_ConvertRGBColorTo4ub(const RGBColor& src); +} + +void ia32_hook_capabilities() +{ + if (ia32_cap(SSE)) + { + ConvertRGBColorTo4ub = sse_ConvertRGBColorTo4ub; + } + else + { + debug_printf("No SSE available. Slow fallback routines will be used.\n"); + } +} diff --git a/source/lib/sysdep/ia32.h b/source/lib/sysdep/ia32.h index d31f6c4513..d5590e71df 100755 --- a/source/lib/sysdep/ia32.h +++ b/source/lib/sysdep/ia32.h @@ -83,6 +83,7 @@ extern bool ia32_cap(CpuCap cap); extern void ia32_get_cpu_info(void); +extern void ia32_hook_capabilities(void); // internal use only diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index f07e1187ee..164519356c 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -779,25 +779,9 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui) debug_set_thread_name("main"); -#if CPU_IA32 - ia32_init(); -#endif - - // If you ever want to catch a particular allocation: - //_CrtSetBreakAlloc(187); - - // no longer set 24 bit (float) precision by default: for - // very long game uptimes (> 1 day; e.g. dedicated server), - // we need full precision when calculating the time. - // if there's a spot where we want to speed up divides|sqrts, - // we can temporarily change precision there. - // _control87(_PC_24, _MCW_PC); - - // detects CPU clock frequency and capabilities, which are prerequisites - // for using the TSC as a timer (desirable due to its high resolution). - // do this before lengthy init so we can time those accurately. - get_cpu_info(); - + // Query CPU capabilities, possibly set some CPU-dependent flags + cpu_init(); + // Do this as soon as possible, because it chdirs // and will mess up the error reporting if anything // crashes before the working directory is set. diff --git a/source/renderer/ModelDefRData.cpp b/source/renderer/ModelDefRData.cpp index c58ce2df39..c4437dbcec 100644 --- a/source/renderer/ModelDefRData.cpp +++ b/source/renderer/ModelDefRData.cpp @@ -8,6 +8,7 @@ #include "graphics/Model.h" #include "renderer/ModelRData.h" #include "renderer/ModelDefRData.h" +#include "renderer/Renderer.h" #define LOG_CATEGORY "graphics" @@ -17,7 +18,7 @@ CModelDefRData* CModelDefRData::m_Submissions = 0; CModelDefRData::CModelDefRData(CModelDef* mdef) - : m_ModelDef(mdef) + : m_ModelDef(mdef), m_Array(false) { m_SubmissionNext = 0; m_SubmissionSlots = 0; @@ -33,8 +34,41 @@ CModelDefRData::~CModelDefRData() // Create and upload shared vertex arrays void CModelDefRData::Build() { + size_t numVertices = m_ModelDef->GetNumVertices(); + + m_UV.type = GL_FLOAT; + m_UV.elems = 2; + m_Array.AddAttribute(&m_UV); + + m_Array.SetNumVertices(numVertices); + m_Array.Layout(); + + SModelVertex* vertices = m_ModelDef->GetVertices(); + VertexArrayIterator UVit = m_UV.GetIterator(); + + for (uint j=0; j < numVertices; ++j, ++UVit) { + (*UVit)[0] = vertices[j].m_U; + (*UVit)[1] = 1.0-vertices[j].m_V; + } + + m_Array.Upload(); + m_Array.FreeBackingStore(); } + +// Setup shared vertex arrays as needed. +void CModelDefRData::PrepareStream(uint streamflags) +{ + if (!(streamflags & STREAM_UV0)) + return; + + u8* base = m_Array.Bind(); + size_t stride = m_Array.GetStride(); + + glTexCoordPointer(2, GL_FLOAT, stride, base + m_UV.offset); +} + + // Submit one model. // Models are sorted into a hash-table to avoid ping-ponging between // different render states later on. diff --git a/source/renderer/ModelDefRData.h b/source/renderer/ModelDefRData.h index 969ed2c37b..0203a64243 100644 --- a/source/renderer/ModelDefRData.h +++ b/source/renderer/ModelDefRData.h @@ -18,6 +18,9 @@ public: CModelDefRData(CModelDef* mdef); virtual ~CModelDefRData(); + // Setup shared vertex arrays required by streamflags + void PrepareStream(uint streamflags); + // Submit one model void Submit(CModelRData* data); // Clear all submissions for this CModelDef @@ -30,6 +33,9 @@ private: private: CModelDef* m_ModelDef; + VertexArray m_Array; + VertexArray::Attribute m_UV; + CModelDefRData* m_SubmissionNext; uint m_SubmissionSlots; std::vector m_SubmissionModels; diff --git a/source/renderer/ModelRData.cpp b/source/renderer/ModelRData.cpp index e99499ea48..36a300cf07 100755 --- a/source/renderer/ModelRData.cpp +++ b/source/renderer/ModelRData.cpp @@ -47,12 +47,12 @@ void CModelRData::Build() m_Position.type = GL_FLOAT; m_Position.elems = 3; m_DynamicArray.AddAttribute(&m_Position); - +/* m_UV.type = GL_FLOAT; m_UV.elems = 2; m_DynamicArray.AddAttribute(&m_UV); - - m_Color.type = GL_FLOAT; +*/ + m_Color.type = GL_UNSIGNED_BYTE; m_Color.elems = 3; m_DynamicArray.AddAttribute(&m_Color); @@ -80,7 +80,7 @@ void CModelRData::Build() } void CModelRData::BuildIndices() -{ +{ CModelDefPtr mdef=m_Model->GetModelDef(); debug_assert(mdef); @@ -100,14 +100,7 @@ void CModelRData::BuildIndices() } } -static SColor3ub ConvertColor(const RGBColor& src) -{ - SColor3ub result; - result.R=clamp(int(src.X*255),0,255); - result.G=clamp(int(src.Y*255),0,255); - result.B=clamp(int(src.Z*255),0,255); - return result; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // SkinPoint: skin the vertex position using it's blend data and given bone matrices @@ -153,6 +146,7 @@ static void SkinNormal(const SModelVertex& vertex,const CMatrix3D* invmatrices,C void CModelRData::BuildStaticVertices() { +/* CModelDefPtr mdef = m_Model->GetModelDef(); size_t numVertices = mdef->GetNumVertices(); SModelVertex* vertices = mdef->GetVertices(); @@ -162,6 +156,7 @@ void CModelRData::BuildStaticVertices() (*UVit)[0] = vertices[j].m_U; (*UVit)[1] = 1.0-vertices[j].m_V; } +*/ } void CModelRData::BuildVertices() @@ -177,7 +172,7 @@ void CModelRData::BuildVertices() // build vertices VertexArrayIterator Position = m_Position.GetIterator(); - VertexArrayIterator Color = m_Color.GetIterator(); + VertexArrayIterator Color = m_Color.GetIterator(); const CMatrix3D* bonematrices=m_Model->GetBoneMatrices(); if (bonematrices) { // boned model - calculate skinned vertex positions/normals @@ -199,12 +194,13 @@ void CModelRData::BuildVertices() PROFILE_START( "lighting vertices" ); // now fill in UV and vertex colour data + CSHCoeffs& shcoeffs = g_Renderer.m_SHCoeffsUnits; + CColor sc = m_Model->GetShadingColor(); + RGBColor shadingcolor(sc.r, sc.g, sc.b); + RGBColor tempcolor; for (uint j=0; jGetShadingColor(); - RGBColor tempcolor; - g_Renderer.m_SHCoeffsUnits.Evaluate(m_Normals[j], tempcolor, - RGBColor(sc.r, sc.g, sc.b)); - Color[j] = tempcolor;//ConvertColor(tempcolor); + shcoeffs.Evaluate(m_Normals[j], tempcolor, shadingcolor); + *(u32*)&Color[j] = ConvertRGBColorTo4ub(tempcolor); } PROFILE_END( "lighting vertices" ); @@ -227,6 +223,8 @@ void CModelRData::RenderStreams(u32 streamflags, bool isplayer) g_Renderer.SetTexture(0,m_Model->GetTexture()); } + ((CModelDefRData*)mdldef->GetRenderData())->PrepareStream(streamflags); + u8* base = m_DynamicArray.Bind(); size_t stride = m_DynamicArray.GetStride(); @@ -243,7 +241,6 @@ void CModelRData::RenderStreams(u32 streamflags, bool isplayer) glDisableClientState(GL_COLOR_ARRAY); } #endif - if (streamflags & STREAM_UV0) glTexCoordPointer(2, GL_FLOAT, stride, base + m_UV.offset); // render the lot size_t numFaces=mdldef->GetNumFaces(); @@ -340,19 +337,39 @@ void CModelRData::RenderModels(u32 streamflags, u32 flags) mdefdata; mdefdata = mdefdata->m_SubmissionNext) { + mdefdata->PrepareStream(streamflags); + for(uint idx = 0; idx < mdefdata->m_SubmissionSlots; ++idx) { - if (!mdefdata->m_SubmissionModels[idx]) - break; + CModelRData* modeldata = mdefdata->m_SubmissionModels[idx]; - for(CModelRData* modeldata = mdefdata->m_SubmissionModels[idx]; - modeldata; - modeldata = modeldata->m_SubmissionNext) + if (streamflags & STREAM_UV0) + g_Renderer.SetTexture(0, modeldata->GetModel()->GetTexture()); + + for(; modeldata; modeldata = modeldata->m_SubmissionNext) { if (flags && !(modeldata->GetModel()->GetFlags()&flags)) continue; - modeldata->RenderStreams(streamflags, false); + CModelDefPtr mdldef = modeldata->GetModel()->GetModelDef(); + + u8* base = modeldata->m_DynamicArray.Bind(); + size_t stride = modeldata->m_DynamicArray.GetStride(); + + glVertexPointer(3, GL_FLOAT, stride, + base + modeldata->m_Position.offset); + if (streamflags & STREAM_COLOR) + glColorPointer(3, modeldata->m_Color.type, stride, + base + modeldata->m_Color.offset); + + // render the lot + size_t numFaces=mdldef->GetNumFaces(); + glDrawRangeElements(GL_TRIANGLES, 0, mdldef->GetNumVertices(), + numFaces*3, GL_UNSIGNED_SHORT, modeldata->m_Indices); + + // bump stats + g_Renderer.m_Stats.m_DrawCalls++; + g_Renderer.m_Stats.m_ModelTris+=numFaces; } } } diff --git a/source/renderer/VertexArray.cpp b/source/renderer/VertexArray.cpp index 173ead343f..0aa7ffac37 100644 --- a/source/renderer/VertexArray.cpp +++ b/source/renderer/VertexArray.cpp @@ -87,12 +87,13 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() } template<> -VertexArrayIterator VertexArray::Attribute::GetIterator() const +VertexArrayIterator VertexArray::Attribute::GetIterator() const { debug_assert(vertexArray); debug_assert(type == GL_FLOAT); + debug_assert(elems >= 2); - return vertexArray->MakeIterator(this); + return vertexArray->MakeIterator(this); } template<>