Simple unoptimized software skinning.

Does not take advantage of the possible reduction in state changes yet.
This commit is contained in:
Henrik Rydgard authored and Henrik Rydgård committed 2013-11-13 18:10:57 +01:00
1 parent 3e6c2f0c78
commit 7e67476b00
9 files changed
+257 -59

No files matched your search

+2
View File
@@ -144,6 +144,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
graphics->Get("RenderingMode", &iRenderingMode, renderingModeDefault);
graphics->Get("SoftwareRendering", &bSoftwareRendering, false);
graphics->Get("HardwareTransform", &bHardwareTransform, true);
graphics->Get("SoftwareSkinning", &bSoftwareSkinning, false);
graphics->Get("TextureFiltering", &iTexFiltering, 1);
// Auto on Windows, 1x elsewhere. Maybe change to 2x on large screens?
#ifdef _WIN32
@@ -401,6 +402,7 @@ void Config::Save() {
graphics->Set("RenderingMode", iRenderingMode);
graphics->Set("SoftwareRendering", bSoftwareRendering);
graphics->Set("HardwareTransform", bHardwareTransform);
graphics->Set("SoftwareSkinning", bSoftwareSkinning);
graphics->Set("TextureFiltering", iTexFiltering);
graphics->Set("InternalResolution", iInternalResolution);
graphics->Set("FrameSkip", iFrameSkip);
+2
View File
@@ -64,6 +64,8 @@ public:
// GFX
bool bSoftwareRendering;
bool bHardwareTransform; // only used in the GLES backend
bool bSoftwareSkinning; // may speed up some games
int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering 2 = Read Framebuffer to memory (CPU) 3 = Read Framebuffer to memory (GPU)
int iTexFiltering; // 1 = off , 2 = nearest , 3 = linear , 4 = linear(CG)
#ifdef BLACKBERRY
+28 -4
View File
@@ -430,6 +430,12 @@ GLES_GPU::GLES_GPU()
commandFlags_[GE_CMD_TEXOFFSETV] &= ~FLAG_FLUSHBEFOREONCHANGE;
}
// TODO: Can't turn this optimization on until we don't decode everything in one go
// but instead decode for every draw call when sw skinning
if (g_Config.bSoftwareSkinning) {
// commandFlags_[GE_CMD_VERTEXTYPE] &= ~FLAG_FLUSHBEFOREONCHANGE;
}
BuildReportingInfo();
}
@@ -868,8 +874,21 @@ void GLES_GPU::ExecuteOpInternal(u32 op, u32 diff) {
break;
case GE_CMD_VERTEXTYPE:
if (diff)
shaderManager_->DirtyUniform(DIRTY_UVSCALEOFFSET);
if (diff) {
if (!g_Config.bSoftwareSkinning) {
shaderManager_->DirtyUniform(DIRTY_UVSCALEOFFSET);
} else if (false) {
// TODO: Can't turn this optimization on until we don't decode everything in one go
// but instead decode for every draw call when sw skinning
if (diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) {
// Restore and flush
gstate.vertType ^= diff;
Flush();
gstate.vertType ^= diff;
shaderManager_->DirtyUniform(DIRTY_UVSCALEOFFSET);
}
}
}
break;
case GE_CMD_REGION1:
@@ -1375,9 +1394,14 @@ void GLES_GPU::ExecuteOpInternal(u32 op, u32 diff) {
int num = gstate.boneMatrixNumber & 0x7F;
float newVal = getFloat24(data);
if (num < 96 && newVal != gstate.boneMatrix[num]) {
Flush();
// Bone matrices should NOT flush when software skinning is enabled!
// TODO: Also check for morph...
// TODO: Can't turn this optimizatoin on until we decode per drawcall when sw skinning.
if (true || !g_Config.bSoftwareSkinning) {
Flush();
shaderManager_->DirtyUniform(DIRTY_BONEMATRIX0 << (num / 12));
}
gstate.boneMatrix[num] = newVal;
shaderManager_->DirtyUniform(DIRTY_BONEMATRIX0 << (num / 12));
}
num++;
gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (num & 0x7F);
+7 -1
View File
@@ -524,8 +524,14 @@ void TransformDrawEngine::DoFlush() {
int vertexCount = 0;
int maxIndex = 0;
bool useElements = true;
// Cannot cache vertex data with morph enabled.
if (g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK)) {
bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK);
// Also avoid caching when software skinning.
if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK))
useCache = false;
if (useCache) {
u32 id = ComputeFastDCID();
auto iter = vai_.find(id);
VertexArrayInfo *vai;
+186 -50
View File
@@ -15,11 +15,10 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "math/lin/matrix4x4.h"
#include "Core/Config.h"
#include "Core/MemMap.h"
#include "GPU/ge_constants.h"
#include "GPU/Math3D.h"
#include "VertexDecoder.h"
#include "VertexShaderGenerator.h"
@@ -36,6 +35,10 @@ static const u8 nrmsize[4] = {0,3,6,12}, nrmalign[4] = {0,1,2,4};
static const u8 possize[4] = {0,3,6,12}, posalign[4] = {0,1,2,4};
static const u8 wtsize[4] = {0,1,2,4}, wtalign[4] = {0,1,2,4};
// When software skinning. This should be stored in registers instead of memory
// when jitting.
float skinMatrix[12];
inline int align(int n, int align) {
return (n + (align - 1)) & ~(align - 1);
}
@@ -112,6 +115,57 @@ void VertexDecoder::Step_WeightsFloat() const
wt[j++] = 0.0f;
}
void VertexDecoder::Step_WeightsU8Skin() const
{
memset(skinMatrix, 0, sizeof(skinMatrix));
u8 *wt = (u8 *)(decoded_ + decFmt.w0off);
const u8 *wdata = (const u8*)(ptr_);
for (int j = 0; j < nweights; j++) {
const float *bone = &gstate.boneMatrix[j * 12];
if (wdata[j] != 0) {
float weight = wdata[j] / 128.0f;
for (int i = 0; i < 12; i++) {
skinMatrix[i] += weight * bone[i];
}
}
}
}
void VertexDecoder::Step_WeightsU16Skin() const
{
memset(skinMatrix, 0, sizeof(skinMatrix));
u16 *wt = (u16 *)(decoded_ + decFmt.w0off);
const u16 *wdata = (const u16*)(ptr_);
for (int j = 0; j < nweights; j++) {
const float *bone = &gstate.boneMatrix[j * 12];
if (wdata[j] != 0) {
float weight = wdata[j] / 32768.0f;
for (int i = 0; i < 12; i++) {
skinMatrix[i] += weight * bone[i];
}
}
}
}
// Float weights should be uncommon, we can live with having to multiply these by 2.0
// to avoid special checks in the vertex shader generator.
// (PSP uses 0.0-2.0 fixed point numbers for weights)
void VertexDecoder::Step_WeightsFloatSkin() const
{
memset(skinMatrix, 0, sizeof(skinMatrix));
float *wt = (float *)(decoded_ + decFmt.w0off);
const float *wdata = (const float*)(ptr_);
for (int j = 0; j < nweights; j++) {
const float *bone = &gstate.boneMatrix[j * 12];
float weight = wdata[j];
if (weight > 0.0) {
for (int i = 0; i < 12; i++) {
skinMatrix[i] += weight * bone[i];
}
}
}
}
void VertexDecoder::Step_TcU8() const
{
// u32 to write two bytes of zeroes for free.
@@ -318,6 +372,29 @@ void VertexDecoder::Step_NormalFloat() const
normal[j] = fv[j];
}
void VertexDecoder::Step_NormalS8Skin() const
{
float *normal = (float *)(decoded_ + decFmt.nrmoff);
const s8 *sv = (const s8*)(ptr_ + nrmoff);
const float fn[3] = { sv[0] / 128.0f, sv[1] / 128.0f, sv[2] / 128.0f };
Norm3ByMatrix43(normal, fn, skinMatrix);
}
void VertexDecoder::Step_NormalS16Skin() const
{
float *normal = (float *)(decoded_ + decFmt.nrmoff);
const s16 *sv = (const s16*)(ptr_ + nrmoff);
const float fn[3] = { sv[0] / 32768.0f, sv[1] / 32768.0f, sv[2] / 32768.0f };
Norm3ByMatrix43(normal, fn, skinMatrix);
}
void VertexDecoder::Step_NormalFloatSkin() const
{
float *normal = (float *)(decoded_ + decFmt.nrmoff);
const float *fn = (const float *)(ptr_ + nrmoff);
Norm3ByMatrix43(normal, fn, skinMatrix);
}
void VertexDecoder::Step_NormalS8Morph() const
{
float *normal = (float *)(decoded_ + decFmt.nrmoff);
@@ -382,6 +459,29 @@ void VertexDecoder::Step_PosFloat() const
memcpy(v, fv, 12);
}
void VertexDecoder::Step_PosS8Skin() const
{
float *pos = (float *)(decoded_ + decFmt.posoff);
const s8 *sv = (const s8*)(ptr_ + posoff);
const float fn[3] = { sv[0] / 128.0f, sv[1] / 128.0f, sv[2] / 128.0f };
Vec3ByMatrix43(pos, fn, skinMatrix);
}
void VertexDecoder::Step_PosS16Skin() const
{
float *pos = (float *)(decoded_ + decFmt.posoff);
const s16 *sv = (const s16*)(ptr_ + posoff);
const float fn[3] = { sv[0] / 32768.0f, sv[1] / 32768.0f, sv[2] / 32768.0f };
Vec3ByMatrix43(pos, fn, skinMatrix);
}
void VertexDecoder::Step_PosFloatSkin() const
{
float *pos = (float *)(decoded_ + decFmt.posoff);
const float *fn = (const float *)(ptr_ + posoff);
Vec3ByMatrix43(pos, fn, skinMatrix);
}
void VertexDecoder::Step_PosS8Through() const
{
float *v = (float *)(decoded_ + decFmt.posoff);
@@ -449,6 +549,13 @@ static const StepFunction wtstep[4] = {
&VertexDecoder::Step_WeightsFloat,
};
static const StepFunction wtstep_skin[4] = {
0,
&VertexDecoder::Step_WeightsU8Skin,
&VertexDecoder::Step_WeightsU16Skin,
&VertexDecoder::Step_WeightsFloatSkin,
};
static const StepFunction tcstep[4] = {
0,
&VertexDecoder::Step_TcU8,
@@ -510,6 +617,13 @@ static const StepFunction nrmstep[4] = {
&VertexDecoder::Step_NormalFloat,
};
static const StepFunction nrmstep_skin[4] = {
0,
&VertexDecoder::Step_NormalS8Skin,
&VertexDecoder::Step_NormalS16Skin,
&VertexDecoder::Step_NormalFloatSkin,
};
static const StepFunction nrmstep_morph[4] = {
0,
&VertexDecoder::Step_NormalS8Morph,
@@ -524,6 +638,13 @@ static const StepFunction posstep[4] = {
&VertexDecoder::Step_PosFloat,
};
static const StepFunction posstep_skin[4] = {
0,
&VertexDecoder::Step_PosS8Skin,
&VertexDecoder::Step_PosS16Skin,
&VertexDecoder::Step_PosFloatSkin,
};
static const StepFunction posstep_morph[4] = {
0,
&VertexDecoder::Step_PosS8Morph,
@@ -564,6 +685,8 @@ void VertexDecoder::SetVertexType(u32 fmt, VertexDecoderJitCache *jitCache) {
DEBUG_LOG(G3D,"VTYPE: THRU=%i TC=%i COL=%i POS=%i NRM=%i WT=%i NW=%i IDX=%i MC=%i", (int)throughmode, tc,col,pos,nrm,weighttype,nweights,idx,morphcount);
}
bool skinInDecode = weighttype != 0 && g_Config.bSoftwareSkinning && morphcount == 1;
if (weighttype) { // && nweights?
weightoff = size;
//size = align(size, wtalign[weighttype]); unnecessary
@@ -571,30 +694,35 @@ void VertexDecoder::SetVertexType(u32 fmt, VertexDecoderJitCache *jitCache) {
if (wtalign[weighttype] > biggest)
biggest = wtalign[weighttype];
steps_[numSteps_++] = wtstep[weighttype];
int fmtBase = DEC_FLOAT_1;
if (weighttype == GE_VTYPE_WEIGHT_8BIT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_U8_1;
} else if (weighttype == GE_VTYPE_WEIGHT_16BIT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_U16_1;
} else if (weighttype == GE_VTYPE_WEIGHT_FLOAT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_FLOAT_1;
}
int numWeights = TranslateNumBones(nweights);
if (numWeights <= 4) {
decFmt.w0off = decOff;
decFmt.w0fmt = fmtBase + numWeights - 1;
decOff += DecFmtSize(decFmt.w0fmt);
if (skinInDecode) {
steps_[numSteps_++] = wtstep_skin[weighttype];
// No visible output
} else {
decFmt.w0off = decOff;
decFmt.w0fmt = fmtBase + 3;
decOff += DecFmtSize(decFmt.w0fmt);
decFmt.w1off = decOff;
decFmt.w1fmt = fmtBase + numWeights - 5;
decOff += DecFmtSize(decFmt.w1fmt);
steps_[numSteps_++] = wtstep[weighttype];
int fmtBase = DEC_FLOAT_1;
if (weighttype == GE_VTYPE_WEIGHT_8BIT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_U8_1;
} else if (weighttype == GE_VTYPE_WEIGHT_16BIT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_U16_1;
} else if (weighttype == GE_VTYPE_WEIGHT_FLOAT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_FLOAT_1;
}
int numWeights = TranslateNumBones(nweights);
if (numWeights <= 4) {
decFmt.w0off = decOff;
decFmt.w0fmt = fmtBase + numWeights - 1;
decOff += DecFmtSize(decFmt.w0fmt);
} else {
decFmt.w0off = decOff;
decFmt.w0fmt = fmtBase + 3;
decOff += DecFmtSize(decFmt.w0fmt);
decFmt.w1off = decOff;
decFmt.w1fmt = fmtBase + numWeights - 5;
decOff += DecFmtSize(decFmt.w1fmt);
}
}
}
@@ -656,26 +784,29 @@ void VertexDecoder::SetVertexType(u32 fmt, VertexDecoderJitCache *jitCache) {
if (nrmalign[nrm] > biggest)
biggest = nrmalign[nrm];
steps_[numSteps_++] = morphcount == 1 ? nrmstep[nrm] : nrmstep_morph[nrm];
if (morphcount == 1) {
// The normal formats match the gl formats perfectly, let's use 'em.
switch (nrm) {
case GE_VTYPE_NRM_8BIT >> GE_VTYPE_NRM_SHIFT: decFmt.nrmfmt = DEC_S8_3; break;
case GE_VTYPE_NRM_16BIT >> GE_VTYPE_NRM_SHIFT: decFmt.nrmfmt = DEC_S16_3; break;
case GE_VTYPE_NRM_FLOAT >> GE_VTYPE_NRM_SHIFT: decFmt.nrmfmt = DEC_FLOAT_3; break;
}
} else {
if (skinInDecode) {
steps_[numSteps_++] = nrmstep_skin[nrm];
// After skinning, we always have three floats.
decFmt.nrmfmt = DEC_FLOAT_3;
}
} else {
steps_[numSteps_++] = morphcount == 1 ? nrmstep[nrm] : nrmstep_morph[nrm];
// Actually, temporarily let's not.
if (morphcount == 1) {
// The normal formats match the gl formats perfectly, let's use 'em.
switch (nrm) {
case GE_VTYPE_NRM_8BIT >> GE_VTYPE_NRM_SHIFT: decFmt.nrmfmt = DEC_S8_3; break;
case GE_VTYPE_NRM_16BIT >> GE_VTYPE_NRM_SHIFT: decFmt.nrmfmt = DEC_S16_3; break;
case GE_VTYPE_NRM_FLOAT >> GE_VTYPE_NRM_SHIFT: decFmt.nrmfmt = DEC_FLOAT_3; break;
}
} else {
decFmt.nrmfmt = DEC_FLOAT_3;
}
}
decFmt.nrmoff = decOff;
decOff += DecFmtSize(decFmt.nrmfmt);
}
if (pos) // there's always a position
{
if (pos) { // there's always a position
size = align(size, posalign[pos]);
posoff = size;
size += possize[pos];
@@ -686,18 +817,23 @@ void VertexDecoder::SetVertexType(u32 fmt, VertexDecoderJitCache *jitCache) {
steps_[numSteps_++] = posstep_through[pos];
decFmt.posfmt = DEC_FLOAT_3;
} else {
steps_[numSteps_++] = morphcount == 1 ? posstep[pos] : posstep_morph[pos];
if (morphcount == 1) {
// The non-through-mode position formats match the gl formats perfectly, let's use 'em.
switch (pos) {
case GE_VTYPE_POS_8BIT >> GE_VTYPE_POS_SHIFT: decFmt.posfmt = DEC_S8_3; break;
case GE_VTYPE_POS_16BIT >> GE_VTYPE_POS_SHIFT: decFmt.posfmt = DEC_S16_3; break;
case GE_VTYPE_POS_FLOAT >> GE_VTYPE_POS_SHIFT: decFmt.posfmt = DEC_FLOAT_3; break;
}
} else {
// Actually, temporarily let's not.
if (skinInDecode) {
steps_[numSteps_++] = posstep_skin[pos];
decFmt.posfmt = DEC_FLOAT_3;
} else {
steps_[numSteps_++] = morphcount == 1 ? posstep[pos] : posstep_morph[pos];
if (morphcount == 1) {
// The non-through-mode position formats match the gl formats perfectly, let's use 'em.
switch (pos) {
case GE_VTYPE_POS_8BIT >> GE_VTYPE_POS_SHIFT: decFmt.posfmt = DEC_S8_3; break;
case GE_VTYPE_POS_16BIT >> GE_VTYPE_POS_SHIFT: decFmt.posfmt = DEC_S16_3; break;
case GE_VTYPE_POS_FLOAT >> GE_VTYPE_POS_SHIFT: decFmt.posfmt = DEC_FLOAT_3; break;
}
} else {
// Actually, temporarily let's not.
decFmt.posfmt = DEC_FLOAT_3;
}
}
}
decFmt.posoff = decOff;
+12
View File
@@ -64,6 +64,10 @@ public:
void Step_WeightsU16() const;
void Step_WeightsFloat() const;
void Step_WeightsU8Skin() const;
void Step_WeightsU16Skin() const;
void Step_WeightsFloatSkin() const;
void Step_TcU8() const;
void Step_TcU16() const;
void Step_TcFloat() const;
@@ -91,6 +95,10 @@ public:
void Step_NormalS16() const;
void Step_NormalFloat() const;
void Step_NormalS8Skin() const;
void Step_NormalS16Skin() const;
void Step_NormalFloatSkin() const;
void Step_NormalS8Morph() const;
void Step_NormalS16Morph() const;
void Step_NormalFloatMorph() const;
@@ -99,6 +107,10 @@ public:
void Step_PosS16() const;
void Step_PosFloat() const;
void Step_PosS8Skin() const;
void Step_PosS16Skin() const;
void Step_PosFloatSkin() const;
void Step_PosS8Morph() const;
void Step_PosS16Morph() const;
void Step_PosFloatMorph() const;
+13 -2
View File
@@ -28,10 +28,14 @@
#include "GPU/Directx9/GPU_DX9.h"
#endif
#include "Core/CoreParameter.h"
#include "Core/Config.h"
#include "Core/System.h"
GPUgstate gstate;
GPUStateCache gstate_c;
// This must be aligned so that the matrices within are aligned.
GPUgstate MEMORY_ALIGNED16(gstate);
// Let's align this one too for good measure.
GPUStateCache MEMORY_ALIGNED16(gstate_c);
GPUInterface *gpu;
GPUDebugInterface *gpuDebug;
GPUStatistics gpuStats;
@@ -200,3 +204,10 @@ void GPUgstate::Restore(u32_le *ptr) {
memcpy(projMatrix, matrices, sizeof(projMatrix)); matrices += sizeof(projMatrix);
memcpy(tgenMatrix, matrices, sizeof(tgenMatrix)); matrices += sizeof(tgenMatrix);
}
bool vertTypeIsSkinningEnabled(u32 vertType) {
if (g_Config.bSoftwareSkinning && ((vertType & GE_VTYPE_MORPHCOUNT_MASK) == 0))
return false;
else
return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE);
}
+3 -1
View File
@@ -18,6 +18,7 @@
#pragma once
#include <cmath>
#include "../Globals.h"
#include "ge_constants.h"
#include "Common/Common.h"
@@ -406,7 +407,8 @@ enum SkipDrawReasonFlags {
SKIPDRAW_BAD_FB_TEXTURE = 4,
};
inline bool vertTypeIsSkinningEnabled(u32 vertType) { return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE); }
bool vertTypeIsSkinningEnabled(u32 vertType);
inline int vertTypeGetNumBoneWeights(u32 vertType) { return 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); }
inline int vertTypeGetWeightMask(u32 vertType) { return vertType & GE_VTYPE_WEIGHT_MASK; }
inline int vertTypeGetTexCoordMask(u32 vertType) { return vertType & GE_VTYPE_TC_MASK; }
+4 -1
View File
@@ -143,10 +143,13 @@ void GameSettingsScreen::CreateViews() {
graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gs->T("VSync")));
#endif
graphicsSettings->Add(new CheckBox(&g_Config.bHardwareTransform, gs->T("Hardware Transform")));
CheckBox *swSkin = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareSkinning, gs->T("Software Skinning")));
graphicsSettings->Add(new CheckBox(&g_Config.bVertexCache, gs->T("Vertex Cache")));
CheckBox *vtxJit = graphicsSettings->Add(new CheckBox(&g_Config.bVertexDecoderJit, gs->T("Vertex Decoder JIT")));
if (PSP_IsInited())
if (PSP_IsInited()) {
swSkin->SetEnabled(false);
vtxJit->SetEnabled(false);
}
graphicsSettings->Add(new CheckBox(&g_Config.bLowQualitySplineBezier, gs->T("LowCurves", "Low quality spline/bezier curves")));