mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-19 00:19:26 +00:00
GPU "dirty" optimization, wip vertexcache
This commit is contained in:
parent
04860322f4
commit
1b1a275dcc
@ -47,16 +47,10 @@ const int flushOnChangedBeforeCommandList[] = {
|
||||
GE_CMD_BLENDMODE,
|
||||
GE_CMD_BLENDFIXEDA,
|
||||
GE_CMD_BLENDFIXEDB,
|
||||
};
|
||||
|
||||
const int flushBeforeCommandList[] = {
|
||||
GE_CMD_BEZIER,
|
||||
GE_CMD_SPLINE,
|
||||
GE_CMD_SIGNAL,
|
||||
GE_CMD_FINISH,
|
||||
GE_CMD_BJUMP,
|
||||
GE_CMD_OFFSETADDR,
|
||||
GE_CMD_REGION1,GE_CMD_REGION2,
|
||||
GE_CMD_TEXOFFSETU,
|
||||
GE_CMD_TEXOFFSETV,
|
||||
GE_CMD_TEXSCALEU,
|
||||
GE_CMD_TEXSCALEV,
|
||||
GE_CMD_CULLFACEENABLE,
|
||||
GE_CMD_TEXTUREMAPENABLE,
|
||||
GE_CMD_LIGHTINGENABLE,
|
||||
@ -67,31 +61,10 @@ const int flushBeforeCommandList[] = {
|
||||
GE_CMD_COLORTESTENABLE,
|
||||
GE_CMD_COLORTESTMASK,
|
||||
GE_CMD_COLORREF,
|
||||
GE_CMD_TEXSCALEU,GE_CMD_TEXSCALEV,
|
||||
GE_CMD_TEXOFFSETU,GE_CMD_TEXOFFSETV,
|
||||
GE_CMD_MINZ,GE_CMD_MAXZ,
|
||||
GE_CMD_FRAMEBUFPTR,
|
||||
GE_CMD_FRAMEBUFWIDTH,
|
||||
GE_CMD_FRAMEBUFPIXFORMAT,
|
||||
GE_CMD_TEXADDR0,
|
||||
GE_CMD_CLUTADDR,
|
||||
GE_CMD_LOADCLUT,
|
||||
GE_CMD_TEXMAPMODE,
|
||||
GE_CMD_TEXSHADELS,
|
||||
GE_CMD_CLUTFORMAT,
|
||||
GE_CMD_TRANSFERSTART,
|
||||
GE_CMD_TEXBUFWIDTH0,
|
||||
GE_CMD_TEXSIZE0,GE_CMD_TEXSIZE1,GE_CMD_TEXSIZE2,GE_CMD_TEXSIZE3,
|
||||
GE_CMD_TEXSIZE4,GE_CMD_TEXSIZE5,GE_CMD_TEXSIZE6,GE_CMD_TEXSIZE7,
|
||||
GE_CMD_ZBUFPTR,
|
||||
GE_CMD_ZBUFWIDTH,
|
||||
GE_CMD_TEXOFFSETU,
|
||||
GE_CMD_TEXOFFSETV,
|
||||
GE_CMD_TEXSCALEU,
|
||||
GE_CMD_TEXSCALEV,
|
||||
GE_CMD_OFFSETY,
|
||||
GE_CMD_OFFSETX,
|
||||
GE_CMD_OFFSETY,
|
||||
GE_CMD_FOG1,
|
||||
GE_CMD_FOG2,
|
||||
GE_CMD_FOGCOLOR,
|
||||
GE_CMD_LMODE,
|
||||
GE_CMD_REVERSENORMAL,
|
||||
GE_CMD_MATERIALUPDATE,
|
||||
@ -128,35 +101,66 @@ const int flushBeforeCommandList[] = {
|
||||
GE_CMD_VIEWPORTZ1,GE_CMD_VIEWPORTZ2,
|
||||
GE_CMD_LIGHTENABLE0,GE_CMD_LIGHTENABLE1,GE_CMD_LIGHTENABLE2,GE_CMD_LIGHTENABLE3,
|
||||
GE_CMD_CULL,
|
||||
GE_CMD_REVERSENORMAL,
|
||||
GE_CMD_PATCHDIVISION,
|
||||
GE_CMD_MATERIALUPDATE,
|
||||
GE_CMD_CLEARMODE,
|
||||
GE_CMD_TEXMAPMODE,
|
||||
GE_CMD_TEXSHADELS,
|
||||
GE_CMD_TEXFUNC,
|
||||
GE_CMD_TEXFILTER,
|
||||
GE_CMD_TEXENVCOLOR,
|
||||
GE_CMD_TEXMODE,
|
||||
GE_CMD_TEXFORMAT,
|
||||
GE_CMD_TEXFLUSH,
|
||||
GE_CMD_TEXWRAP,
|
||||
GE_CMD_ZTESTENABLE,
|
||||
GE_CMD_STENCILTESTENABLE,
|
||||
GE_CMD_STENCILOP,
|
||||
GE_CMD_STENCILTEST,
|
||||
GE_CMD_ZTEST,
|
||||
GE_CMD_FOG1,
|
||||
GE_CMD_FOG2,
|
||||
GE_CMD_FOGCOLOR,
|
||||
GE_CMD_MASKRGB,
|
||||
GE_CMD_MASKALPHA,
|
||||
};
|
||||
|
||||
const int flushBeforeCommandList[] = {
|
||||
GE_CMD_BEZIER,
|
||||
GE_CMD_SPLINE,
|
||||
GE_CMD_SIGNAL,
|
||||
GE_CMD_FINISH,
|
||||
GE_CMD_BJUMP,
|
||||
GE_CMD_OFFSETADDR,
|
||||
GE_CMD_REGION1,GE_CMD_REGION2,
|
||||
GE_CMD_FRAMEBUFPTR,
|
||||
GE_CMD_FRAMEBUFWIDTH,
|
||||
GE_CMD_FRAMEBUFPIXFORMAT,
|
||||
GE_CMD_TEXADDR0,
|
||||
GE_CMD_CLUTADDR,
|
||||
GE_CMD_LOADCLUT,
|
||||
GE_CMD_CLUTFORMAT,
|
||||
GE_CMD_TRANSFERSTART,
|
||||
GE_CMD_TEXBUFWIDTH0,
|
||||
GE_CMD_TEXSIZE0,GE_CMD_TEXSIZE1,GE_CMD_TEXSIZE2,GE_CMD_TEXSIZE3,
|
||||
GE_CMD_TEXSIZE4,GE_CMD_TEXSIZE5,GE_CMD_TEXSIZE6,GE_CMD_TEXSIZE7,
|
||||
GE_CMD_ZBUFPTR,
|
||||
GE_CMD_ZBUFWIDTH,
|
||||
GE_CMD_OFFSETY,
|
||||
GE_CMD_OFFSETX,
|
||||
GE_CMD_OFFSETY,
|
||||
GE_CMD_TEXFLUSH,
|
||||
GE_CMD_MORPHWEIGHT0,GE_CMD_MORPHWEIGHT1,GE_CMD_MORPHWEIGHT2,GE_CMD_MORPHWEIGHT3,
|
||||
GE_CMD_MORPHWEIGHT4,GE_CMD_MORPHWEIGHT5,GE_CMD_MORPHWEIGHT6,GE_CMD_MORPHWEIGHT7,
|
||||
// These handle their own flushing.
|
||||
/*
|
||||
GE_CMD_WORLDMATRIXNUMBER,
|
||||
GE_CMD_WORLDMATRIXDATA,
|
||||
GE_CMD_VIEWMATRIXNUMBER,
|
||||
GE_CMD_VIEWMATRIXDATA,
|
||||
GE_CMD_PROJMATRIXNUMBER,
|
||||
GE_CMD_PROJMATRIXDATA,
|
||||
GE_CMD_TGENMATRIXNUMBER,
|
||||
GE_CMD_TGENMATRIXDATA,
|
||||
GE_CMD_BONEMATRIXNUMBER,
|
||||
GE_CMD_MASKRGB,
|
||||
GE_CMD_MASKALPHA,
|
||||
GE_CMD_BONEMATRIXDATA,
|
||||
*/
|
||||
};
|
||||
|
||||
GLES_GPU::GLES_GPU(int renderWidth, int renderHeight)
|
||||
@ -466,9 +470,13 @@ static void LeaveClearMode() {
|
||||
|
||||
void GLES_GPU::PreExecuteOp(u32 op, u32 diff) {
|
||||
u32 cmd = op >> 24;
|
||||
|
||||
if (flushBeforeCommand_[cmd] == 1 || (diff && flushBeforeCommand_[cmd] == 2))
|
||||
{
|
||||
if (dumpThisFrame_) {
|
||||
NOTICE_LOG(G3D, "================ FLUSH ================");
|
||||
}
|
||||
transformDraw_.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
||||
@ -1054,10 +1062,14 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
||||
case GE_CMD_WORLDMATRIXDATA:
|
||||
{
|
||||
int num = gstate.worldmtxnum & 0xF;
|
||||
if (num < 12)
|
||||
gstate.worldMatrix[num++] = getFloat24(data);
|
||||
float newVal = getFloat24(data);
|
||||
if (num < 12 && newVal != gstate.worldMatrix[num]) {
|
||||
Flush();
|
||||
gstate.worldMatrix[num] = getFloat24(data);
|
||||
shaderManager_->DirtyUniform(DIRTY_WORLDMATRIX);
|
||||
}
|
||||
num++;
|
||||
gstate.worldmtxnum = (gstate.worldmtxnum & 0xFF000000) | (num & 0xF);
|
||||
shaderManager_->DirtyUniform(DIRTY_WORLDMATRIX);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1068,10 +1080,14 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
||||
case GE_CMD_VIEWMATRIXDATA:
|
||||
{
|
||||
int num = gstate.viewmtxnum & 0xF;
|
||||
if (num < 12)
|
||||
gstate.viewMatrix[num++] = getFloat24(data);
|
||||
float newVal = getFloat24(data);
|
||||
if (num < 12 && newVal != gstate.viewMatrix[num]) {
|
||||
Flush();
|
||||
gstate.viewMatrix[num] = newVal;
|
||||
shaderManager_->DirtyUniform(DIRTY_VIEWMATRIX);
|
||||
}
|
||||
num++;
|
||||
gstate.viewmtxnum = (gstate.viewmtxnum & 0xFF000000) | (num & 0xF);
|
||||
shaderManager_->DirtyUniform(DIRTY_VIEWMATRIX);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1082,10 +1098,15 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
||||
case GE_CMD_PROJMATRIXDATA:
|
||||
{
|
||||
int num = gstate.projmtxnum & 0xF;
|
||||
gstate.projMatrix[num++] = getFloat24(data);
|
||||
float newVal = getFloat24(data);
|
||||
if (newVal != gstate.projMatrix[num]) {
|
||||
Flush();
|
||||
gstate.projMatrix[num] = newVal;
|
||||
shaderManager_->DirtyUniform(DIRTY_PROJMATRIX);
|
||||
}
|
||||
num++;
|
||||
gstate.projmtxnum = (gstate.projmtxnum & 0xFF000000) | (num & 0xF);
|
||||
}
|
||||
shaderManager_->DirtyUniform(DIRTY_PROJMATRIX);
|
||||
break;
|
||||
|
||||
case GE_CMD_TGENMATRIXNUMBER:
|
||||
@ -1095,11 +1116,15 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
||||
case GE_CMD_TGENMATRIXDATA:
|
||||
{
|
||||
int num = gstate.texmtxnum & 0xF;
|
||||
if (num < 12)
|
||||
gstate.tgenMatrix[num++] = getFloat24(data);
|
||||
float newVal = getFloat24(data);
|
||||
if (newVal != gstate.tgenMatrix[num] && num < 12) {
|
||||
Flush();
|
||||
gstate.tgenMatrix[num] = newVal;
|
||||
shaderManager_->DirtyUniform(DIRTY_TEXMATRIX);
|
||||
}
|
||||
num++;
|
||||
gstate.texmtxnum = (gstate.texmtxnum & 0xFF000000) | (num & 0xF);
|
||||
}
|
||||
shaderManager_->DirtyUniform(DIRTY_TEXMATRIX);
|
||||
break;
|
||||
|
||||
case GE_CMD_BONEMATRIXNUMBER:
|
||||
@ -1109,10 +1134,13 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
||||
case GE_CMD_BONEMATRIXDATA:
|
||||
{
|
||||
int num = gstate.boneMatrixNumber & 0x7F;
|
||||
shaderManager_->DirtyUniform(DIRTY_BONEMATRIX0 << (num / 12));
|
||||
if (num < 96) {
|
||||
gstate.boneMatrix[num++] = getFloat24(data);
|
||||
float newVal = getFloat24(data);
|
||||
if (newVal != gstate.boneMatrix[num] && num < 96) {
|
||||
Flush();
|
||||
gstate.boneMatrix[num] = newVal;
|
||||
shaderManager_->DirtyUniform(DIRTY_BONEMATRIX0 << (num / 12));
|
||||
}
|
||||
num++;
|
||||
gstate.boneMatrixNumber = (gstate.boneMatrixNumber & 0xFF000000) | (num & 0x7F);
|
||||
}
|
||||
break;
|
||||
|
@ -293,13 +293,13 @@ void LinkedShader::updateUniforms() {
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (u_lightdiffuse[i] != -1 && (dirtyUniforms & (DIRTY_LIGHT0 << i))) {
|
||||
glUniform3fv(u_lightpos[i], 1, gstate_c.lightpos[i]);
|
||||
glUniform3fv(u_lightdir[i], 1, gstate_c.lightdir[i]);
|
||||
glUniform3fv(u_lightatt[i], 1, gstate_c.lightatt[i]);
|
||||
glUniform3fv(u_lightambient[i], 1, gstate_c.lightColor[0][i]);
|
||||
glUniform3fv(u_lightdiffuse[i], 1, gstate_c.lightColor[1][i]);
|
||||
glUniform3fv(u_lightspecular[i], 1, gstate_c.lightColor[2][i]);
|
||||
if (dirtyUniforms & (DIRTY_LIGHT0 << i)) {
|
||||
if (u_lightpos[i] != -1) glUniform3fv(u_lightpos[i], 1, gstate_c.lightpos[i]);
|
||||
if (u_lightdir[i] != -1) glUniform3fv(u_lightdir[i], 1, gstate_c.lightdir[i]);
|
||||
if (u_lightatt[i] != -1) glUniform3fv(u_lightatt[i], 1, gstate_c.lightatt[i]);
|
||||
if (u_lightambient[i] != -1) glUniform3fv(u_lightambient[i], 1, gstate_c.lightColor[0][i]);
|
||||
if (u_lightdiffuse[i] != -1) glUniform3fv(u_lightdiffuse[i], 1, gstate_c.lightColor[1][i]);
|
||||
if (u_lightspecular[i] != -1) glUniform3fv(u_lightspecular[i], 1, gstate_c.lightColor[2][i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "ShaderManager.h"
|
||||
#include "TextureCache.h"
|
||||
|
||||
const GLint aLookup[] = {
|
||||
const GLint aLookup[11] = {
|
||||
GL_DST_COLOR,
|
||||
GL_ONE_MINUS_DST_COLOR,
|
||||
GL_SRC_ALPHA,
|
||||
@ -23,7 +23,7 @@ const GLint aLookup[] = {
|
||||
GL_CONSTANT_COLOR, // FIXA
|
||||
};
|
||||
|
||||
const GLint bLookup[] = {
|
||||
const GLint bLookup[11] = {
|
||||
GL_SRC_COLOR,
|
||||
GL_ONE_MINUS_SRC_COLOR,
|
||||
GL_SRC_ALPHA,
|
||||
@ -36,6 +36,7 @@ const GLint bLookup[] = {
|
||||
GL_ONE_MINUS_DST_ALPHA, // should be 2x
|
||||
GL_CONSTANT_COLOR, // FIXB
|
||||
};
|
||||
|
||||
const GLint eqLookup[] = {
|
||||
GL_FUNC_ADD,
|
||||
GL_FUNC_SUBTRACT,
|
||||
@ -107,6 +108,8 @@ void ApplyDrawState(int prim) {
|
||||
int blendFuncA = gstate.getBlendFuncA();
|
||||
int blendFuncB = gstate.getBlendFuncB();
|
||||
int blendFuncEq = gstate.getBlendEq();
|
||||
if (blendFuncA > GE_SRCBLEND_FIXA) blendFuncA = GE_SRCBLEND_FIXA;
|
||||
if (blendFuncB > GE_DSTBLEND_FIXB) blendFuncB = GE_DSTBLEND_FIXB;
|
||||
|
||||
glstate.blendEquation.set(eqLookup[blendFuncEq]);
|
||||
|
||||
|
@ -86,12 +86,14 @@ void TransformDrawEngine::DestroyDeviceObjects() {
|
||||
glDeleteBuffers(NUM_VBOS, &ebo_[0]);
|
||||
memset(vbo_, 0, sizeof(vbo_));
|
||||
memset(ebo_, 0, sizeof(ebo_));
|
||||
ClearTrackedVertexArrays();
|
||||
}
|
||||
|
||||
void TransformDrawEngine::GLLost() {
|
||||
// The objects have already been deleted.
|
||||
memset(vbo_, 0, sizeof(vbo_));
|
||||
memset(ebo_, 0, sizeof(ebo_));
|
||||
ClearTrackedVertexArrays();
|
||||
InitDeviceObjects();
|
||||
}
|
||||
|
||||
@ -620,7 +622,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make a cache for glEnableVertexAttribArray and glVertexAttribPtr states,
|
||||
// TODO: Add a post-transform cache here for multi-RECTANGLES only.
|
||||
// Might help for text drawing.
|
||||
|
||||
// these spam the gDebugger log.
|
||||
const int vertexSize = sizeof(transformed[0]);
|
||||
|
||||
@ -837,123 +841,121 @@ void TransformDrawEngine::Flush() {
|
||||
LinkedShader *program = shaderManager_->ApplyShader(prim);
|
||||
|
||||
if (CanUseHardwareTransform(prevPrim_)) {
|
||||
bool useVBO = g_Config.bUseVBO;
|
||||
GLuint vbo = 0, ebo = 0;
|
||||
int vertexCount = 0;
|
||||
if (useVBO) {
|
||||
if (g_Config.bVertexCache) {
|
||||
u32 id = ComputeFastDCID();
|
||||
auto iter = vai_.find(id);
|
||||
VertexArrayInfo *vai;
|
||||
if (vai_.find(id) != vai_.end()) {
|
||||
// We've seen this before. Could have been a cached draw.
|
||||
vai = iter->second;
|
||||
} else {
|
||||
vai = new VertexArrayInfo();
|
||||
vai->decFmt = dec.GetDecVtxFmt();
|
||||
vai_[id] = vai;
|
||||
}
|
||||
vai->lastFrame = gpuStats.numFrames;
|
||||
// A pretty little state machine.
|
||||
switch (vai->status) {
|
||||
case VertexArrayInfo::VAI_INBUFFERABLE:
|
||||
goto useSoftware;
|
||||
|
||||
case VertexArrayInfo::VAI_NEW:
|
||||
{
|
||||
// Haven't seen this one before.
|
||||
u32 dataHash = ComputeHash();
|
||||
vai->hash = dataHash;
|
||||
vai->status = VertexArrayInfo::VAI_HASHING;
|
||||
DecodeVerts(); // writes to indexGen
|
||||
vertexCount = indexGen.VertexCount();
|
||||
prim = indexGen.Prim();
|
||||
if (!CanUseHardwareTransform(indexGen.Prim()))
|
||||
{
|
||||
vai->status = VertexArrayInfo::VAI_INBUFFERABLE;
|
||||
goto useSoftware;
|
||||
}
|
||||
goto rotateVBO;
|
||||
}
|
||||
|
||||
// Hashing - still gaining confidence about the buffer.
|
||||
// But if we get this far it's likely to be worth creating a vertex buffer.
|
||||
case VertexArrayInfo::VAI_HASHING:
|
||||
{
|
||||
u32 newHash = ComputeHash();
|
||||
vai->numDraws++;
|
||||
if (vai->numDraws > 100000) {
|
||||
vai->status = VertexArrayInfo::VAI_RELIABLE;
|
||||
}
|
||||
if (newHash == vai->hash) {
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
} else {
|
||||
vai->status = VertexArrayInfo::VAI_UNRELIABLE;
|
||||
}
|
||||
if (vai->vbo == 0) {
|
||||
DecodeVerts(); // TODO : Remove
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->prim = indexGen.Prim();
|
||||
glGenBuffers(1, &vai->vbo);
|
||||
|
||||
// TODO: in some cases we can avoid creating an element buffer.
|
||||
// If there's only been one primitive type, and it's either TRIANGLES, LINES or POINTS,
|
||||
// there is no need for the index buffer we built. We can then use glDrawArrays instead
|
||||
// for a very minor speed boost.
|
||||
//int seen = indexGen.SeenPrims() | 0x83204820;
|
||||
//seen == (1 << GE_PRIM_TRIANGLES) || seen == (1 << GE_PRIM_LINES) || seen == (1 << GE_PRIM_POINTS)
|
||||
bool useElements = true;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vai->vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, dec.GetDecVtxFmt().stride * indexGen.MaxIndex(), decoded, GL_STATIC_DRAW);
|
||||
if (useElements) {
|
||||
glGenBuffers(1, &vai->ebo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vai->ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short) * indexGen.VertexCount(), (GLvoid *)decIndex, GL_STATIC_DRAW);
|
||||
}
|
||||
} else {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vai->vbo);
|
||||
if (vai->ebo)
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vai->ebo);
|
||||
}
|
||||
vbo = vai->vbo;
|
||||
ebo = vai->ebo;
|
||||
vertexCount = vai->numVerts;
|
||||
prim = vai->prim;
|
||||
break;
|
||||
}
|
||||
|
||||
// Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time.
|
||||
case VertexArrayInfo::VAI_RELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
// DecodeVerts(); // TODO : Remove
|
||||
vbo = vai->vbo;
|
||||
ebo = vai->ebo;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
if (ebo)
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
vertexCount = vai->numVerts;
|
||||
prim = vai->prim;
|
||||
break;
|
||||
}
|
||||
|
||||
case VertexArrayInfo::VAI_UNRELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
DecodeVerts();
|
||||
vertexCount = indexGen.VertexCount();
|
||||
prim = indexGen.Prim();
|
||||
goto rotateVBO;
|
||||
}
|
||||
}
|
||||
if (g_Config.bVertexCache) {
|
||||
u32 id = ComputeFastDCID();
|
||||
auto iter = vai_.find(id);
|
||||
VertexArrayInfo *vai;
|
||||
if (vai_.find(id) != vai_.end()) {
|
||||
// We've seen this before. Could have been a cached draw.
|
||||
vai = iter->second;
|
||||
} else {
|
||||
DecodeVerts();
|
||||
vai = new VertexArrayInfo();
|
||||
vai->decFmt = dec.GetDecVtxFmt();
|
||||
vai_[id] = vai;
|
||||
}
|
||||
vai->lastFrame = gpuStats.numFrames;
|
||||
// A pretty little state machine.
|
||||
switch (vai->status) {
|
||||
case VertexArrayInfo::VAI_INBUFFERABLE:
|
||||
goto useSoftware;
|
||||
|
||||
case VertexArrayInfo::VAI_NEW:
|
||||
{
|
||||
// Haven't seen this one before.
|
||||
u32 dataHash = ComputeHash();
|
||||
vai->hash = dataHash;
|
||||
vai->status = VertexArrayInfo::VAI_HASHING;
|
||||
DecodeVerts(); // writes to indexGen
|
||||
vertexCount = indexGen.VertexCount();
|
||||
prim = indexGen.Prim();
|
||||
if (!CanUseHardwareTransform(indexGen.Prim()))
|
||||
{
|
||||
vai->status = VertexArrayInfo::VAI_INBUFFERABLE;
|
||||
goto useSoftware;
|
||||
}
|
||||
goto rotateVBO;
|
||||
}
|
||||
|
||||
// Hashing - still gaining confidence about the buffer.
|
||||
// But if we get this far it's likely to be worth creating a vertex buffer.
|
||||
case VertexArrayInfo::VAI_HASHING:
|
||||
{
|
||||
u32 newHash = ComputeHash();
|
||||
vai->numDraws++;
|
||||
if (vai->numDraws > 100000) {
|
||||
vai->status = VertexArrayInfo::VAI_RELIABLE;
|
||||
}
|
||||
if (newHash == vai->hash) {
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
} else {
|
||||
vai->status = VertexArrayInfo::VAI_UNRELIABLE;
|
||||
}
|
||||
if (vai->vbo == 0) {
|
||||
DecodeVerts(); // TODO : Remove
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->prim = indexGen.Prim();
|
||||
glGenBuffers(1, &vai->vbo);
|
||||
|
||||
// TODO: in some cases we can avoid creating an element buffer.
|
||||
// If there's only been one primitive type, and it's either TRIANGLES, LINES or POINTS,
|
||||
// there is no need for the index buffer we built. We can then use glDrawArrays instead
|
||||
// for a very minor speed boost.
|
||||
//int seen = indexGen.SeenPrims() | 0x83204820;
|
||||
//seen == (1 << GE_PRIM_TRIANGLES) || seen == (1 << GE_PRIM_LINES) || seen == (1 << GE_PRIM_POINTS)
|
||||
bool useElements = true;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vai->vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, dec.GetDecVtxFmt().stride * indexGen.MaxIndex(), decoded, GL_STATIC_DRAW);
|
||||
if (useElements) {
|
||||
glGenBuffers(1, &vai->ebo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vai->ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short) * indexGen.VertexCount(), (GLvoid *)decIndex, GL_STATIC_DRAW);
|
||||
}
|
||||
} else {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vai->vbo);
|
||||
if (vai->ebo)
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vai->ebo);
|
||||
}
|
||||
vbo = vai->vbo;
|
||||
ebo = vai->ebo;
|
||||
vertexCount = vai->numVerts;
|
||||
prim = vai->prim;
|
||||
break;
|
||||
}
|
||||
|
||||
// Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time.
|
||||
case VertexArrayInfo::VAI_RELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
// DecodeVerts(); // TODO : Remove
|
||||
vbo = vai->vbo;
|
||||
ebo = vai->ebo;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
if (ebo)
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
vertexCount = vai->numVerts;
|
||||
prim = vai->prim;
|
||||
break;
|
||||
}
|
||||
|
||||
case VertexArrayInfo::VAI_UNRELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
DecodeVerts();
|
||||
vertexCount = indexGen.VertexCount();
|
||||
prim = indexGen.Prim();
|
||||
goto rotateVBO;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DecodeVerts();
|
||||
rotateVBO:
|
||||
if (g_Config.bUseVBO) {
|
||||
// Just rotate VBO.
|
||||
vbo = vbo_[curVbo_];
|
||||
ebo = ebo_[curVbo_];
|
||||
vertexCount = indexGen.VertexCount();
|
||||
curVbo_++;
|
||||
if (curVbo_ == NUM_VBOS)
|
||||
curVbo_ = 0;
|
||||
@ -962,6 +964,7 @@ rotateVBO:
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short) * indexGen.VertexCount(), (GLvoid *)decIndex, GL_STREAM_DRAW);
|
||||
}
|
||||
vertexCount = indexGen.VertexCount();
|
||||
}
|
||||
|
||||
DEBUG_LOG(G3D, "Flush prim %i! %i verts in one go", prim, vertexCount);
|
||||
@ -971,15 +974,11 @@ rotateVBO:
|
||||
glDrawArrays(glprim[prim], 0, vertexCount);
|
||||
} else {
|
||||
glDrawElements(glprim[prim], vertexCount, GL_UNSIGNED_SHORT, vbo ? 0 : (GLvoid*)decIndex);
|
||||
if (useVBO) {
|
||||
//glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short) * indexGen.VertexCount(), 0, GL_DYNAMIC_DRAW);
|
||||
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
if (useVBO) {
|
||||
// glBufferData(GL_ARRAY_BUFFER, dec.GetDecVtxFmt().stride * indexGen.MaxIndex(), 0, GL_DYNAMIC_DRAW);
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
if (ebo)
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
if (vbo)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
} else {
|
||||
useSoftware:
|
||||
DecodeVerts();
|
||||
|
Loading…
x
Reference in New Issue
Block a user