Move pipeline back into VertexLoader. Started work on VertexLoaderManager, which will cache VertexLoaders. (yep, the design plan changed a little bit).

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@956 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2008-10-25 12:35:55 +00:00
parent 3a3eebc313
commit bc79d22f5e
12 changed files with 219 additions and 116 deletions

View File

@ -58,6 +58,13 @@ enum
FORMAT_32B_8888 = 5,
};
enum
{
VAT_0_FRACBITS = 0x3e0001f0,
VAT_1_FRACBITS = 0x07c3e1f0,
VAT_2_FRACBITS = 0xf87c3e1f,
};
#pragma pack(4)
union TVtxDesc
{

View File

@ -70,26 +70,20 @@ typedef void (LOADERDECL *TPipelineFunction)(const void *);
// all the data loading code must always be made compatible.
class NativeVertexFormat
{
u8* m_compiledCode;
public:
NativeVertexFormat();
~NativeVertexFormat();
void Initialize(const TVtxDesc &vtx_desc, const TVtxAttr &vtx_attr);
void RunPipelineOnce(const TVtxAttr &vtx_attr) const;
void SetupVertexPointers() {
// Cast a pointer to compiled code to a pointer to a function taking no parameters, through a (void *) cast first to
// get around type checking errors, and call it.
((void (*)())(void*)m_compiledCode)();
}
void SetupVertexPointers() const;
// TODO: move these in under private:
int m_VBVertexStride; // PC-side vertex stride
int m_VBStridePad;
u32 m_components; // VB_HAS_X. Bitmask telling what vertex components are present.
TPipelineFunction m_PipelineStages[32];
int m_numPipelineStages;
u8* m_compiledCode;
};
#endif // _NATIVEVERTEXFORMAT_H

View File

@ -764,6 +764,14 @@
RelativePath=".\Src\VertexLoader_TextCoord.h"
>
</File>
<File
RelativePath=".\Src\VertexLoaderManager.cpp"
>
</File>
<File
RelativePath=".\Src\VertexLoaderManager.h"
>
</File>
<File
RelativePath=".\Src\VertexManager.cpp"
>

View File

@ -37,10 +37,6 @@
// Here's some global state. We only use this to keep track of what we've sent to the OpenGL state
// machine.
DECLARE_IMPORT(glNormalPointer);
DECLARE_IMPORT(glVertexPointer);
DECLARE_IMPORT(glColorPointer);
@ -49,7 +45,6 @@ DECLARE_IMPORT(glTexCoordPointer);
NativeVertexFormat::NativeVertexFormat()
{
m_compiledCode = (u8 *)AllocateExecutableMemory(COMPILED_CODE_SIZE, false);
m_numPipelineStages = 0;
if (m_compiledCode) {
memset(m_compiledCode, 0, COMPILED_CODE_SIZE);
}
@ -61,6 +56,12 @@ NativeVertexFormat::~NativeVertexFormat()
m_compiledCode = 0;
}
void NativeVertexFormat::SetupVertexPointers() const {
// Cast a pointer to compiled code to a pointer to a function taking no parameters, through a (void *) cast first to
// get around type checking errors, and call it.
((void (*)())(void*)m_compiledCode)();
}
void NativeVertexFormat::Initialize(const TVtxDesc &vtx_desc, const TVtxAttr &vtx_attr)
{
using namespace Gen;
@ -178,7 +179,7 @@ void NativeVertexFormat::Initialize(const TVtxDesc &vtx_desc, const TVtxAttr &vt
offset += 1;
}
_assert_(offset+m_VBStridePad == m_VBVertexStride);
_assert_(offset + m_VBStridePad == m_VBVertexStride);
Util::EmitEpilogue(6);
if (Gen::GetCodePtr() - (u8*)m_compiledCode > COMPILED_CODE_SIZE)
@ -188,9 +189,3 @@ void NativeVertexFormat::Initialize(const TVtxDesc &vtx_desc, const TVtxAttr &vt
SetCodePtr(old_code_ptr);
}
void NativeVertexFormat::RunPipelineOnce(const TVtxAttr &vtx_attr) const
{
for (int i = 0; i < m_numPipelineStages; i++)
m_PipelineStages[i](&vtx_attr);
}

View File

@ -29,6 +29,7 @@
#include "OpcodeDecoding.h"
#include "VertexLoader.h"
#include "VertexLoaderManager.h"
#include "VertexManager.h"
#include "VertexShaderManager.h"
@ -55,7 +56,7 @@ static void ExecuteDisplayList(u32 address, u32 size)
// temporarily swap dl and non-dl (small "hack" for the stats)
Statistics::SwapDL();
while((u32)(g_pVideoData - startAddress) < size)
while ((u32)(g_pVideoData - startAddress) < size)
{
Decode();
}
@ -78,7 +79,7 @@ bool FifoCommandRunnable()
u8 Cmd = DataPeek8(0);
u32 iCommandSize = 0;
switch(Cmd)
switch (Cmd)
{
case GX_NOP:
// Hm, this means that we scan over nop streams pretty slowly...
@ -210,7 +211,7 @@ static void Decode()
{
u32 SubCmd = DataReadU8();
u32 Value = DataReadU32();
VertexManager::LoadCPReg(SubCmd,Value);
LoadCPReg(SubCmd, Value);
INCSTAT(stats.thisFrame.numCPLoads);
}
break;
@ -218,13 +219,13 @@ static void Decode()
case GX_LOAD_XF_REG:
{
u32 Cmd2 = DataReadU32();
int dwTransferSize = ((Cmd2>>16)&15) + 1;
int dwTransferSize = ((Cmd2 >> 16) & 15) + 1;
u32 dwAddress = Cmd2 & 0xFFFF;
// TODO - speed this up. pshufb?
static u32 pData[16];
for (int i=0; i<dwTransferSize; i++)
for (int i = 0; i < dwTransferSize; i++)
pData[i] = DataReadU32();
VertexShaderMngr::LoadXFReg(dwTransferSize,dwAddress,pData);
VertexShaderMngr::LoadXFReg(dwTransferSize, dwAddress, pData);
INCSTAT(stats.thisFrame.numXFLoads);
}
break;
@ -272,9 +273,10 @@ static void Decode()
{
// load vertices (use computed vertex size from FifoCommandRunnable above)
u16 numVertices = DataReadU16();
if (numVertices > 0) {
g_VertexLoaders[Cmd & GX_VAT_MASK].RunVertices((Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices);
}
VertexLoaderManager::RunVertices(
Cmd & GX_VAT_MASK, // Vertex loader index (0 - 7)
(Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT,
numVertices);
}
else
{

View File

@ -23,6 +23,7 @@ files = [
'VertexManager.cpp',
'VertexLoader.cpp',
'VertexLoader_Normal.cpp',
'VertexLoaderManager.cpp',
'VertexShaderManager.cpp',
'XFB.cpp',
'GUI/ConfigDlg.cpp',

View File

@ -29,6 +29,7 @@
#include "Render.h"
#include "VertexShader.h"
#include "VertexManager.h"
#include "VertexLoaderManager.h"
#include "VertexLoader.h"
#include "BPStructs.h"
#include "DataReader.h"
@ -115,6 +116,7 @@ VertexLoader::VertexLoader()
{
m_VertexSize = 0;
m_AttrDirty = AD_DIRTY;
m_numPipelineStages = 0;
VertexLoader_Normal::Init();
}
@ -126,15 +128,15 @@ int VertexLoader::ComputeVertexSize()
{
if (m_AttrDirty == AD_CLEAN) {
// Compare the 33 desc bits.
if (m_VtxDesc.Hex0 == VertexManager::GetVtxDesc().Hex0 &&
(m_VtxDesc.Hex1 & 1) == (VertexManager::GetVtxDesc().Hex1 & 1))
if (m_VtxDesc.Hex0 == GetVtxDesc().Hex0 &&
(m_VtxDesc.Hex1 & 1) == (GetVtxDesc().Hex1 & 1))
return m_VertexSize;
m_VtxDesc.Hex = VertexManager::GetVtxDesc().Hex;
m_VtxDesc.Hex = GetVtxDesc().Hex;
}
else {
// Attributes are dirty so we have to recompute everything anyway.
m_VtxDesc.Hex = VertexManager::GetVtxDesc().Hex;
m_VtxDesc.Hex = GetVtxDesc().Hex;
}
m_AttrDirty = AD_DIRTY;
@ -248,7 +250,8 @@ void VertexLoader::PrepareForVertexFormat()
if (m_AttrDirty == AD_CLEAN)
{
// Check if local cached desc (in this VL) matches global desc
if (m_VtxDesc.Hex0 == VertexManager::GetVtxDesc().Hex0 && (m_VtxDesc.Hex1 & 1)==(VertexManager::GetVtxDesc().Hex1 & 1))
if (m_VtxDesc.Hex0 == GetVtxDesc().Hex0 &&
(m_VtxDesc.Hex1 & 1) == (GetVtxDesc().Hex1 & 1))
{
return; // same
}
@ -258,19 +261,21 @@ void VertexLoader::PrepareForVertexFormat()
m_AttrDirty = AD_CLEAN;
}
m_VtxDesc.Hex = VertexManager::GetVtxDesc().Hex;
m_VtxDesc.Hex = GetVtxDesc().Hex;
// Reset pipeline
m_numPipelineStages = 0;
// It's a bit ugly that we poke inside m_NativeFmt in this function. Planning to fix this.
m_NativeFmt.m_VBStridePad = 0;
m_NativeFmt.m_VBVertexStride = 0;
m_NativeFmt.m_numPipelineStages = 0;
m_NativeFmt.m_components = 0;
// m_VBVertexStride for texmtx and posmtx is computed later when writing.
// Position Matrix Index
if (m_VtxDesc.PosMatIdx) {
m_NativeFmt.m_PipelineStages[m_NativeFmt.m_numPipelineStages++] = PosMtx_ReadDirect_UByte;
m_PipelineStages[m_numPipelineStages++] = PosMtx_ReadDirect_UByte;
m_NativeFmt.m_components |= VB_HAS_POSMTXIDX;
}
@ -508,7 +513,7 @@ void VertexLoader::SetupTexCoord(int num, int mode, int format, int elements, in
void VertexLoader::WriteCall(TPipelineFunction func)
{
m_NativeFmt.m_PipelineStages[m_NativeFmt.m_numPipelineStages++] = func;
m_PipelineStages[m_numPipelineStages++] = func;
}
void VertexLoader::RunVertices(int primitive, int count)
@ -626,7 +631,7 @@ void VertexLoader::RunVertices(int primitive, int count)
colIndex = 0;
s_texmtxwrite = s_texmtxread = 0;
m_NativeFmt.RunPipelineOnce(m_VtxAttr);
RunPipelineOnce();
VertexManager::s_pCurBufferPointer += m_NativeFmt.m_VBStridePad;
PRIM_LOG("\n");
@ -635,3 +640,9 @@ void VertexLoader::RunVertices(int primitive, int count)
if (startv < count)
VertexManager::AddVertices(primitive, count - startv + extraverts);
}
void VertexLoader::RunPipelineOnce() const
{
for (int i = 0; i < m_numPipelineStages; i++)
m_PipelineStages[i](&m_VtxAttr);
}

View File

@ -59,8 +59,13 @@ private:
// PC vertex format, + converter ======
NativeVertexFormat m_NativeFmt;
// Pipeline. To be JIT compiled in the future.
TPipelineFunction m_PipelineStages[32];
int m_numPipelineStages;
void SetupColor(int num, int _iMode, int _iFormat, int _iElements);
void SetupTexCoord(int num, int _iMode, int _iFormat, int _iElements, int _iFrac);
void RunPipelineOnce() const;
public:
// constructor
@ -79,7 +84,8 @@ public:
void SetVAT_group0(u32 _group0)
{
if ((m_group0.Hex & ~0x3e0001f0) != (_group0 & ~0x3e0001f0)) {
// ignore frac bits - we don't need to recompute if all that's changed was the frac bits.
if ((m_group0.Hex & ~VAT_0_FRACBITS) != (_group0 & ~VAT_0_FRACBITS)) {
m_AttrDirty = AD_VAT_DIRTY;
}
m_group0.Hex = _group0;
@ -102,7 +108,7 @@ public:
void SetVAT_group1(u32 _group1)
{
if ((m_group1.Hex & ~0x7c3e1f0) != (_group1 & ~0x7c3e1f0)) {
if ((m_group1.Hex & ~VAT_1_FRACBITS) != (_group1 & ~VAT_1_FRACBITS)) {
m_AttrDirty = AD_VAT_DIRTY;
}
m_group1.Hex = _group1;
@ -122,7 +128,7 @@ public:
void SetVAT_group2(u32 _group2)
{
if ((m_group2.Hex & ~0xf87c3e1f) != (_group2 & ~0xf87c3e1f)) {
if ((m_group2.Hex & ~VAT_2_FRACBITS) != (_group2 & ~VAT_2_FRACBITS)) {
m_AttrDirty = AD_VAT_DIRTY;
}
m_group2.Hex = _group2;

View File

@ -0,0 +1,79 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program 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, version 2.0.
// This program 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "VertexShaderManager.h"
#include "VertexLoader.h"
#include "VertexLoaderManager.h"
// The one and only vtx_desc
TVtxDesc g_vtx_desc;
// There are 8 vtx_attr structures. They will soon live here.
const TVtxDesc &GetVtxDesc()
{
return g_vtx_desc;
}
namespace VertexLoaderManager {
void Init() {
g_vtx_desc.Hex = 0;
}
void Shutdown() {
}
void RunVertices(int vtx_attr_group, int primitive, int count)
{
if (!count)
return;
// TODO - grab load the correct vertex loader if anything is dirty.
g_VertexLoaders[vtx_attr_group].RunVertices(primitive, count);
}
} // namespace
void LoadCPReg(u32 sub_cmd, u32 value)
{
switch (sub_cmd & 0xF0)
{
case 0x30:
VertexShaderMngr::SetTexMatrixChangedA(value);
break;
case 0x40:
VertexShaderMngr::SetTexMatrixChangedB(value);
break;
case 0x50:
g_vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits
g_vtx_desc.Hex |= value;
break;
case 0x60:
g_vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits
g_vtx_desc.Hex |= (u64)value << 17;
break;
case 0x70: g_VertexLoaders[sub_cmd & 7].SetVAT_group0(value); _assert_((sub_cmd & 0x0F) < 8); break;
case 0x80: g_VertexLoaders[sub_cmd & 7].SetVAT_group1(value); _assert_((sub_cmd & 0x0F) < 8); break;
case 0x90: g_VertexLoaders[sub_cmd & 7].SetVAT_group2(value); _assert_((sub_cmd & 0x0F) < 8); break;
case 0xA0: arraybases[sub_cmd & 0xF] = value & 0xFFFFFFFF; break;
case 0xB0: arraystrides[sub_cmd & 0xF] = value & 0xFF; break;
}
}

View File

@ -0,0 +1,39 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program 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, version 2.0.
// This program 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _VERTEXLOADERMANAGER_H
#define _VERTEXLOADERMANAGER_H
#include "Common.h"
namespace VertexLoaderManager
{
void Init();
void Shutdown();
void RunVertices(int vtx_attr_group, int primitive, int count);
// TODO - don't expose these like this.
static u8* s_pCurBufferPointer;
};
const TVtxDesc &GetVtxDesc();
// Might move this into its own file later.
void LoadCPReg(u32 SubCmd, u32 Value);
#endif // _VERTEXLOADERMANAGER_H

View File

@ -19,14 +19,21 @@
#define MAX_BUFFER_SIZE 0x4000
// internal state for loading vertices
extern NativeVertexFormat *g_nativeVertexFmt;
namespace VertexManager
{
static GLuint s_vboBuffers[0x40] = {0};
static int s_nCurVBOIndex = 0; // current free buffer
static u8 *s_pBaseBufferPointer = NULL;
static std::vector< std::pair<int, int> > s_vStoredPrimitives; // every element, mode and count to be passed to glDrawArrays
static u32 s_prevcomponents; // previous state set
u8* VertexManager::s_pCurBufferPointer = NULL;
TVtxDesc VertexManager::s_GlobalVtxDesc;
u8* s_pCurBufferPointer = NULL;
TVtxDesc s_GlobalVtxDesc;
static const GLenum c_primitiveType[8] =
{
@ -40,14 +47,10 @@ static const GLenum c_primitiveType[8] =
GL_POINTS
};
// internal state for loading vertices
extern NativeVertexFormat *g_nativeVertexFmt;
bool VertexManager::Init()
bool Init()
{
Destroy();
s_GlobalVtxDesc.Hex = 0;
s_prevcomponents = 0;
s_pBaseBufferPointer = (u8*)AllocateMemoryPages(MAX_BUFFER_SIZE);
s_pCurBufferPointer = s_pBaseBufferPointer;
@ -67,7 +70,7 @@ bool VertexManager::Init()
return true;
}
void VertexManager::Destroy()
void Destroy()
{
FreeMemoryPages(s_pBaseBufferPointer, MAX_BUFFER_SIZE); s_pBaseBufferPointer = s_pCurBufferPointer = NULL;
glDeleteBuffers(ARRAYSIZE(s_vboBuffers), s_vboBuffers);
@ -78,14 +81,14 @@ void VertexManager::Destroy()
ResetBuffer();
}
void VertexManager::ResetBuffer()
void ResetBuffer()
{
s_nCurVBOIndex = (s_nCurVBOIndex + 1) % ARRAYSIZE(s_vboBuffers);
s_pCurBufferPointer = s_pBaseBufferPointer;
s_vStoredPrimitives.resize(0);
}
void VertexManager::ResetComponents()
void ResetComponents()
{
s_prevcomponents = 0;
glDisableVertexAttribArray(SHADER_POSMTX_ATTRIB);
@ -98,12 +101,12 @@ void VertexManager::ResetComponents()
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
int VertexManager::GetRemainingSize()
int GetRemainingSize()
{
return MAX_BUFFER_SIZE - (int)(s_pCurBufferPointer - s_pBaseBufferPointer);
}
void VertexManager::AddVertices(int primitive, int numvertices)
void AddVertices(int primitive, int numvertices)
{
_assert_( numvertices > 0 );
@ -116,7 +119,7 @@ void VertexManager::AddVertices(int primitive, int numvertices)
#endif
}
void VertexManager::Flush()
void Flush()
{
if (s_vStoredPrimitives.size() == 0)
return;
@ -298,37 +301,8 @@ void VertexManager::Flush()
ResetBuffer();
}
void VertexManager::LoadCPReg(u32 sub_cmd, u32 value)
{
switch (sub_cmd & 0xF0)
{
case 0x30:
VertexShaderMngr::SetTexMatrixChangedA(value);
break;
case 0x40:
VertexShaderMngr::SetTexMatrixChangedB(value);
break;
case 0x50:
s_GlobalVtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
s_GlobalVtxDesc.Hex |= value;
break;
case 0x60:
s_GlobalVtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
s_GlobalVtxDesc.Hex |= (u64)value << 17;
break;
case 0x70: g_VertexLoaders[sub_cmd & 7].SetVAT_group0(value); _assert_((sub_cmd & 0x0F) < 8); break;
case 0x80: g_VertexLoaders[sub_cmd & 7].SetVAT_group1(value); _assert_((sub_cmd & 0x0F) < 8); break;
case 0x90: g_VertexLoaders[sub_cmd & 7].SetVAT_group2(value); _assert_((sub_cmd & 0x0F) < 8); break;
case 0xA0: arraybases[sub_cmd & 0xF] = value & 0xFFFFFFFF; break;
case 0xB0: arraystrides[sub_cmd & 0xF] = value & 0xFF; break;
}
}
// This should move into NativeVertexFormat
void VertexManager::EnableComponents(u32 components)
void EnableComponents(u32 components)
{
if (s_prevcomponents != components) {
if (s_vStoredPrimitives.size() != 0)
@ -384,3 +358,5 @@ void VertexManager::EnableComponents(u32 components)
s_prevcomponents = components;
}
}
} // namespace

View File

@ -21,40 +21,25 @@
#include "CPMemory.h"
// TODO - clarify the role of this class.
// Methods to manage and cache the global state of vertex streams and flushing streams
// Also handles processing the CP registers
class VertexManager
// Handles the OpenGL details of drawing lots of vertices quickly.
// Other functionality is moving out.
namespace VertexManager
{
static TVtxDesc s_GlobalVtxDesc;
bool Init();
void Destroy();
public:
enum Collection
{
C_NOTHING=0,
C_TRIANGLES=1,
C_LINES=2,
C_POINTS=3
};
void ResetBuffer();
void ResetComponents();
static bool Init();
static void Destroy();
void AddVertices(int primitive, int numvertices);
void Flush(); // flushes the current buffer
static void ResetBuffer();
static void ResetComponents();
int GetRemainingSize(); // remaining space in the current buffer.
static void AddVertices(int primitive, int numvertices);
static void Flush(); // flushes the current buffer
void EnableComponents(u32 components); // very implementation specific - D3D9 won't need this one.
static int GetRemainingSize();
static TVtxDesc &GetVtxDesc() {return s_GlobalVtxDesc; }
static void LoadCPReg(u32 SubCmd, u32 Value);
static void EnableComponents(u32 components);
// TODO - don't expose these like this.
static u8* s_pCurBufferPointer;
// TODO: move, rename.
extern u8* s_pCurBufferPointer;
};
#endif // _VERTEXMANAGER_H