mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-11 08:39:28 +01:00
Merge pull request #9906 from hrydgard/fastrunloop-optimize
GPU FastRunLoop optimizations
This commit is contained in:
commit
d60bb27cd9
7 files changed
+156
-88
No files matched your search
@@ -314,7 +314,6 @@ public:
|
||||
const VkPhysicalDeviceFeatures &GetFeaturesEnabled() const { return featuresEnabled_; }
|
||||
const VulkanPhysicalDeviceInfo &GetDeviceInfo() const { return deviceInfo_; }
|
||||
|
||||
|
||||
private:
|
||||
VkSemaphore acquireSemaphore;
|
||||
VkSemaphore renderingCompleteSemaphore;
|
||||
@@ -381,7 +380,6 @@ private:
|
||||
|
||||
VulkanDeleteList deleteList;
|
||||
};
|
||||
|
||||
FrameData frame_[2];
|
||||
int curFrame_;
|
||||
|
||||
|
||||
+33
-15
@@ -73,6 +73,7 @@ struct D3D11CommandTableEntry {
|
||||
GPU_D3D11::CmdFunc func;
|
||||
};
|
||||
|
||||
// This table gets crunched into a faster form by init.
|
||||
static const D3D11CommandTableEntry commandTable[] = {
|
||||
// Changes that dirty the current texture.
|
||||
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_TexSize0 },
|
||||
@@ -88,7 +89,6 @@ static const D3D11CommandTableEntry commandTable[] = {
|
||||
|
||||
// Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack...
|
||||
{ GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_LoadClut },
|
||||
{ GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart },
|
||||
};
|
||||
|
||||
GPU_D3D11::CommandInfo GPU_D3D11::cmdInfo_[256]{};
|
||||
@@ -389,27 +389,38 @@ void GPU_D3D11::CopyDisplayToOutputInternal() {
|
||||
void GPU_D3D11::FastRunLoop(DisplayList &list) {
|
||||
PROFILE_THIS_SCOPE("gpuloop");
|
||||
const CommandInfo *cmdInfo = cmdInfo_;
|
||||
for (; downcount > 0; --downcount) {
|
||||
int dc = downcount;
|
||||
for (; dc > 0; --dc) {
|
||||
// We know that display list PCs have the upper nibble == 0 - no need to mask the pointer
|
||||
const u32 op = *(const u32 *)(Memory::base + list.pc);
|
||||
const u32 cmd = op >> 24;
|
||||
const CommandInfo info = cmdInfo[cmd];
|
||||
const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two
|
||||
const CommandInfo &info = cmdInfo[cmd];
|
||||
const u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
// Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check.
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0...
|
||||
if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
|
||||
(this->*info.func)(op, diff);
|
||||
} else if (diff) {
|
||||
uint64_t dirty = info.flags >> 8;
|
||||
if (dirty)
|
||||
gstate_c.Dirty(dirty);
|
||||
if (diff == 0) {
|
||||
if (info.flags & FLAG_EXECUTE) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
}
|
||||
} else {
|
||||
uint64_t flags = info.flags;
|
||||
if (flags & FLAG_FLUSHBEFOREONCHANGE) {
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op;
|
||||
if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
} else {
|
||||
uint64_t dirty = flags >> 8;
|
||||
if (dirty)
|
||||
gstate_c.Dirty(dirty);
|
||||
}
|
||||
}
|
||||
list.pc += 4;
|
||||
}
|
||||
downcount = 0;
|
||||
}
|
||||
|
||||
void GPU_D3D11::FinishDeferred() {
|
||||
@@ -533,6 +544,7 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) {
|
||||
#endif
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitPrim(verts, inds, prim, count, vertexType, &bytesRead);
|
||||
|
||||
int vertexCost = EstimatePerVertexCost() * count;
|
||||
@@ -546,6 +558,8 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -596,6 +610,7 @@ void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
|
||||
|
||||
if (gstate_c.bezier)
|
||||
@@ -608,6 +623,8 @@ void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_D3D11::Execute_Spline(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -664,6 +681,7 @@ void GPU_D3D11::Execute_Spline(u32 op, u32 diff) {
|
||||
}
|
||||
}
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
|
||||
|
||||
if (gstate_c.spline)
|
||||
|
||||
+34
-16
@@ -57,6 +57,7 @@ struct D3D9CommandTableEntry {
|
||||
GPU_DX9::CmdFunc func;
|
||||
};
|
||||
|
||||
// This table gets crunched into a faster form by init.
|
||||
static const D3D9CommandTableEntry commandTable[] = {
|
||||
// Changes that dirty the current texture.
|
||||
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_TexSize0 },
|
||||
@@ -72,7 +73,6 @@ static const D3D9CommandTableEntry commandTable[] = {
|
||||
|
||||
// Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack...
|
||||
{ GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_LoadClut },
|
||||
{ GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart },
|
||||
};
|
||||
|
||||
GPU_DX9::CommandInfo GPU_DX9::cmdInfo_[256];
|
||||
@@ -356,27 +356,38 @@ void GPU_DX9::CopyDisplayToOutputInternal() {
|
||||
void GPU_DX9::FastRunLoop(DisplayList &list) {
|
||||
PROFILE_THIS_SCOPE("gpuloop");
|
||||
const CommandInfo *cmdInfo = cmdInfo_;
|
||||
for (; downcount > 0; --downcount) {
|
||||
int dc = downcount;
|
||||
for (; dc > 0; --dc) {
|
||||
// We know that display list PCs have the upper nibble == 0 - no need to mask the pointer
|
||||
const u32 op = *(const u32 *)(Memory::base + list.pc);
|
||||
const u32 cmd = op >> 24;
|
||||
const CommandInfo info = cmdInfo[cmd];
|
||||
const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two
|
||||
const CommandInfo &info = cmdInfo[cmd];
|
||||
const u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
// Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check.
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0...
|
||||
if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
|
||||
(this->*info.func)(op, diff);
|
||||
} else if (diff) {
|
||||
uint64_t dirty = info.flags >> 8;
|
||||
if (dirty)
|
||||
gstate_c.Dirty(dirty);
|
||||
if (diff == 0) {
|
||||
if (info.flags & FLAG_EXECUTE) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
}
|
||||
} else {
|
||||
uint64_t flags = info.flags;
|
||||
if (flags & FLAG_FLUSHBEFOREONCHANGE) {
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op;
|
||||
if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
} else {
|
||||
uint64_t dirty = flags >> 8;
|
||||
if (dirty)
|
||||
gstate_c.Dirty(dirty);
|
||||
}
|
||||
}
|
||||
list.pc += 4;
|
||||
}
|
||||
downcount = 0;
|
||||
}
|
||||
|
||||
void GPU_DX9::FinishDeferred() {
|
||||
@@ -386,7 +397,7 @@ void GPU_DX9::FinishDeferred() {
|
||||
|
||||
inline void GPU_DX9::CheckFlushOp(int cmd, u32 diff) {
|
||||
const u8 cmdFlags = cmdInfo_[cmd].flags;
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
|
||||
if (dumpThisFrame_) {
|
||||
NOTICE_LOG(G3D, "================ FLUSH ================");
|
||||
}
|
||||
@@ -499,6 +510,7 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) {
|
||||
#endif
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitPrim(verts, inds, prim, count, vertexType, &bytesRead);
|
||||
|
||||
int vertexCost = EstimatePerVertexCost() * count;
|
||||
@@ -512,6 +524,8 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_DX9::Execute_Bezier(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -551,6 +565,7 @@ void GPU_DX9::Execute_Bezier(u32 op, u32 diff) {
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
bool patchFacing = gstate.patchfacing & 1;
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
|
||||
|
||||
// After drawing, we advance pointers - see SubmitPrim which does the same.
|
||||
@@ -559,6 +574,8 @@ void GPU_DX9::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_DX9::Execute_Spline(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -601,6 +618,7 @@ void GPU_DX9::Execute_Spline(u32 op, u32 diff) {
|
||||
bool patchFacing = gstate.patchfacing & 1;
|
||||
u32 vertType = gstate.vertType;
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
|
||||
|
||||
// After drawing, we advance pointers - see SubmitPrim which does the same.
|
||||
|
||||
+30
-17
@@ -76,7 +76,6 @@ static const GLESCommandTableEntry commandTable[] = {
|
||||
|
||||
// Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack...
|
||||
{ GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_GLES::Execute_LoadClut },
|
||||
{ GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart },
|
||||
};
|
||||
|
||||
GPU_GLES::CommandInfo GPU_GLES::cmdInfo_[256];
|
||||
@@ -567,22 +566,29 @@ void GPU_GLES::FastRunLoop(DisplayList &list) {
|
||||
// We know that display list PCs have the upper nibble == 0 - no need to mask the pointer
|
||||
const u32 op = *(const u32 *)(Memory::base + list.pc);
|
||||
const u32 cmd = op >> 24;
|
||||
const CommandInfo info = cmdInfo[cmd];
|
||||
const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two
|
||||
const CommandInfo &info = cmdInfo[cmd];
|
||||
const u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
// Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check.
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0...
|
||||
if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
} else if (diff) {
|
||||
uint64_t dirty = info.flags >> 8;
|
||||
if (dirty)
|
||||
gstate_c.Dirty(dirty);
|
||||
if (diff == 0) {
|
||||
if (info.flags & FLAG_EXECUTE) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
}
|
||||
} else {
|
||||
uint64_t flags = info.flags;
|
||||
if (flags & FLAG_FLUSHBEFOREONCHANGE) {
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op;
|
||||
if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
} else {
|
||||
uint64_t dirty = flags >> 8;
|
||||
if (dirty)
|
||||
gstate_c.Dirty(dirty);
|
||||
}
|
||||
}
|
||||
list.pc += 4;
|
||||
}
|
||||
@@ -596,7 +602,7 @@ void GPU_GLES::FinishDeferred() {
|
||||
|
||||
inline void GPU_GLES::CheckFlushOp(int cmd, u32 diff) {
|
||||
const u8 cmdFlags = cmdInfo_[cmd].flags;
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
|
||||
if (dumpThisFrame_) {
|
||||
NOTICE_LOG(G3D, "================ FLUSH ================");
|
||||
}
|
||||
@@ -676,6 +682,7 @@ void GPU_GLES::Execute_Prim(u32 op, u32 diff) {
|
||||
#endif
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitPrim(verts, inds, prim, count, gstate.vertType, &bytesRead);
|
||||
|
||||
int vertexCost = EstimatePerVertexCost();
|
||||
@@ -720,6 +727,8 @@ void GPU_GLES::Execute_VertexTypeSkinning(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_GLES::Execute_Bezier(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -770,6 +779,7 @@ void GPU_GLES::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
|
||||
|
||||
if (gstate_c.bezier)
|
||||
@@ -782,6 +792,8 @@ void GPU_GLES::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_GLES::Execute_Spline(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -839,6 +851,7 @@ void GPU_GLES::Execute_Spline(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
|
||||
|
||||
if (gstate_c.spline)
|
||||
|
||||
+12
-20
@@ -111,10 +111,12 @@ const CommonCommandTableEntry commonCommandTable[] = {
|
||||
{ GE_CMD_LOGICOPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
|
||||
|
||||
{ GE_CMD_TEXMAPMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE },
|
||||
{ GE_CMD_TEXSCALEU, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexScaleU },
|
||||
{ GE_CMD_TEXSCALEV, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexScaleV },
|
||||
{ GE_CMD_TEXOFFSETU, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexOffsetU },
|
||||
{ GE_CMD_TEXOFFSETV, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexOffsetV },
|
||||
|
||||
// These are read on every SubmitPrim, no need for dirtying or flushing.
|
||||
{ GE_CMD_TEXSCALEU },
|
||||
{ GE_CMD_TEXSCALEV },
|
||||
{ GE_CMD_TEXOFFSETU },
|
||||
{ GE_CMD_TEXOFFSETV },
|
||||
|
||||
// TEXSIZE0 is handled by each backend.
|
||||
{ GE_CMD_TEXSIZE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
|
||||
@@ -278,6 +280,7 @@ const CommonCommandTableEntry commonCommandTable[] = {
|
||||
{ GE_CMD_TRANSFERSRCPOS, 0 },
|
||||
{ GE_CMD_TRANSFERDSTPOS, 0 },
|
||||
{ GE_CMD_TRANSFERSIZE, 0 },
|
||||
{ GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart },
|
||||
|
||||
// We don't use the dither table.
|
||||
{ GE_CMD_DITH0 },
|
||||
@@ -1267,6 +1270,8 @@ void GPUCommon::Execute_Ret(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_End(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
easy_guard guard(listLock);
|
||||
const u32 prev = Memory::ReadUnchecked_U32(currentList->pc - 4);
|
||||
UpdatePC(currentList->pc, currentList->pc);
|
||||
@@ -1423,22 +1428,6 @@ void GPUCommon::Execute_End(u32 op, u32 diff) {
|
||||
}
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_TexScaleU(u32 op, u32 diff) {
|
||||
gstate_c.uv.uScale = getFloat24(op);
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_TexScaleV(u32 op, u32 diff) {
|
||||
gstate_c.uv.vScale = getFloat24(op);
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_TexOffsetU(u32 op, u32 diff) {
|
||||
gstate_c.uv.uOff = getFloat24(op);
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_TexOffsetV(u32 op, u32 diff) {
|
||||
gstate_c.uv.vOff = getFloat24(op);
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_TexLevel(u32 op, u32 diff) {
|
||||
if (diff == 0xFFFFFFFF) return;
|
||||
|
||||
@@ -1451,6 +1440,7 @@ void GPUCommon::Execute_TexLevel(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Bezier(u32 op, u32 diff) {
|
||||
Flush();
|
||||
// This also make skipping drawing very effective.
|
||||
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
|
||||
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
|
||||
@@ -1494,6 +1484,7 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Spline(u32 op, u32 diff) {
|
||||
Flush();
|
||||
// This also make skipping drawing very effective.
|
||||
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
|
||||
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
|
||||
@@ -1568,6 +1559,7 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_BlockTransferStart(u32 op, u32 diff) {
|
||||
Flush();
|
||||
// and take appropriate action. This is a block transfer between RAM and VRAM, or vice versa.
|
||||
// Can we skip this on SkipDraw?
|
||||
DoBlockTransfer(gstate_c.skipDrawReason);
|
||||
|
||||
+18
-1
@@ -9,7 +9,9 @@
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <atomic>
|
||||
#elif defined(_M_SSE)
|
||||
#endif
|
||||
|
||||
#if defined(_M_SSE)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
@@ -196,6 +198,21 @@ public:
|
||||
GPUgstate GetGState() override;
|
||||
void SetCmdValue(u32 op) override;
|
||||
|
||||
void UpdateUVScaleOffset() {
|
||||
#ifdef _M_SSE
|
||||
__m128i values = _mm_slli_epi32(_mm_load_si128((const __m128i *)&gstate.texscaleu), 8);
|
||||
_mm_storeu_si128((__m128i *)&gstate_c.uv, values);
|
||||
#elif PPSSPP_PLATFORM(ARM_NEON)
|
||||
const uint32x4_t values = vshlq_n_u32(vld1q_u32(&gstate.texscaleu), 8);
|
||||
vst1q_u32(&gstate_c.uv, values);
|
||||
#else
|
||||
gstate_c.uv.uScale = getFloat24(gstate.texscaleu);
|
||||
gstate_c.uv.vScale = getFloat24(gstate.texscalev);
|
||||
gstate_c.uv.uOff = getFloat24(gstate.texoffsetu);
|
||||
gstate_c.uv.vOff = getFloat24(gstate.texoffsetv);
|
||||
#endif
|
||||
}
|
||||
|
||||
DisplayList* getList(int listid) override {
|
||||
return &dls[listid];
|
||||
}
|
||||
|
||||
+29
-17
@@ -56,7 +56,6 @@ struct VulkanCommandTableEntry {
|
||||
GPU_Vulkan::CommandInfo GPU_Vulkan::cmdInfo_[256];
|
||||
|
||||
// This table gets crunched into a faster form by init.
|
||||
// TODO: Share this table between the backends. Will have to make another indirection for the function pointers though..
|
||||
static const VulkanCommandTableEntry commandTable[] = {
|
||||
// Changes that dirty the current texture.
|
||||
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_TexSize0 },
|
||||
@@ -72,7 +71,6 @@ static const VulkanCommandTableEntry commandTable[] = {
|
||||
|
||||
// Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack...
|
||||
{ GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_LoadClut },
|
||||
{ GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart },
|
||||
};
|
||||
|
||||
GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
|
||||
@@ -398,22 +396,29 @@ void GPU_Vulkan::FastRunLoop(DisplayList &list) {
|
||||
// We know that display list PCs have the upper nibble == 0 - no need to mask the pointer
|
||||
const u32 op = *(const u32 *)(Memory::base + list.pc);
|
||||
const u32 cmd = op >> 24;
|
||||
const CommandInfo info = cmdInfo[cmd];
|
||||
const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two
|
||||
const CommandInfo &info = cmdInfo[cmd];
|
||||
const u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
// Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check.
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0...
|
||||
if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
} else if (diff) {
|
||||
uint64_t dirty = info.flags >> 8;
|
||||
if (dirty)
|
||||
gstate_c.Dirty(dirty);
|
||||
if (diff == 0) {
|
||||
if (info.flags & FLAG_EXECUTE) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
}
|
||||
} else {
|
||||
uint64_t flags = info.flags;
|
||||
if (flags & FLAG_FLUSHBEFOREONCHANGE) {
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op;
|
||||
if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) {
|
||||
downcount = dc;
|
||||
(this->*info.func)(op, diff);
|
||||
dc = downcount;
|
||||
} else {
|
||||
uint64_t dirty = flags >> 8;
|
||||
if (dirty)
|
||||
gstate_c.Dirty(dirty);
|
||||
}
|
||||
}
|
||||
list.pc += 4;
|
||||
}
|
||||
@@ -507,6 +512,7 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) {
|
||||
#endif
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitPrim(verts, inds, prim, count, gstate.vertType, &bytesRead);
|
||||
|
||||
int vertexCost = EstimatePerVertexCost() * count;
|
||||
@@ -551,6 +557,8 @@ void GPU_Vulkan::Execute_VertexTypeSkinning(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -601,6 +609,7 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
}
|
||||
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
|
||||
|
||||
if (gstate_c.bezier)
|
||||
@@ -613,6 +622,8 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -670,6 +681,7 @@ void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
|
||||
|
||||
if (gstate_c.spline)
|
||||
|
||||
Reference in new issue
Block a user