Vulkan: Fix Prescale UV

This commit is contained in:
Henrik Rydgard 2016-03-21 18:50:11 +01:00
parent e8758c1ea0
commit 20f227cc4d
4 changed files with 95 additions and 65 deletions

View file

@ -121,14 +121,14 @@ TransformDrawEngine::TransformDrawEngine()
: decodedVerts_(0), : decodedVerts_(0),
prevPrim_(GE_PRIM_INVALID), prevPrim_(GE_PRIM_INVALID),
lastVType_(-1), lastVType_(-1),
shaderManager_(0), shaderManager_(nullptr),
textureCache_(0), textureCache_(nullptr),
framebufferManager_(0), framebufferManager_(nullptr),
numDrawCalls(0), numDrawCalls(0),
vertexCountInDrawCalls(0), vertexCountInDrawCalls(0),
decodeCounter_(0), decodeCounter_(0),
dcid_(0), dcid_(0),
uvScale(0), uvScale(nullptr),
fboTexNeedBind_(false), fboTexNeedBind_(false),
fboTexBound_(false) { fboTexBound_(false) {
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL; decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL;

View file

@ -71,6 +71,7 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan)
framebufferManager_(nullptr), framebufferManager_(nullptr),
numDrawCalls(0), numDrawCalls(0),
vertexCountInDrawCalls(0), vertexCountInDrawCalls(0),
uvScale(nullptr),
fboTexNeedBind_(false), fboTexNeedBind_(false),
fboTexBound_(false), fboTexBound_(false),
curFrame_(0), curFrame_(0),
@ -92,6 +93,10 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan)
indexGen.Setup(decIndex); indexGen.Setup(decIndex);
if (g_Config.bPrescaleUV) {
uvScale = new UVScale[MAX_DEFERRED_DRAW_CALLS];
}
// All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated. // All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated.
VkDescriptorSetLayoutBinding bindings[5]; VkDescriptorSetLayoutBinding bindings[5];
bindings[0].descriptorCount = 1; bindings[0].descriptorCount = 1;
@ -202,6 +207,7 @@ DrawEngineVulkan::~DrawEngineVulkan() {
nullTexture_->Destroy(); nullTexture_->Destroy();
delete nullTexture_; delete nullTexture_;
} }
delete[] uvScale;
} }
void DrawEngineVulkan::BeginFrame() { void DrawEngineVulkan::BeginFrame() {
@ -312,6 +318,10 @@ void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim,
dc.indexUpperBound = vertexCount - 1; dc.indexUpperBound = vertexCount - 1;
} }
if (uvScale) {
uvScale[numDrawCalls] = gstate_c.uv;
}
numDrawCalls++; numDrawCalls++;
vertexCountInDrawCalls += vertexCount; vertexCountInDrawCalls += vertexCount;
@ -324,6 +334,70 @@ void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim,
} }
} }
void DrawEngineVulkan::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) {
const DeferredDrawCall &dc = drawCalls[i];
indexGen.SetIndex(decodedVerts);
int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound;
void *inds = dc.inds;
if (dc.indexType == GE_VTYPE_IDX_NONE >> GE_VTYPE_IDX_SHIFT) {
// Decode the verts and apply morphing. Simple.
dec_->DecodeVerts(dest + decodedVerts * (int)dec_->GetDecVtxFmt().stride,
dc.verts, indexLowerBound, indexUpperBound);
decodedVerts += indexUpperBound - indexLowerBound + 1;
indexGen.AddPrim(dc.prim, dc.vertexCount);
} else {
// It's fairly common that games issue long sequences of PRIM calls, with differing
// inds pointer but the same base vertex pointer. We'd like to reuse vertices between
// these as much as possible, so we make sure here to combine as many as possible
// into one nice big drawcall, sharing data.
// 1. Look ahead to find the max index, only looking as "matching" drawcalls.
// Expand the lower and upper bounds as we go.
int lastMatch = i;
const int total = numDrawCalls;
for (int j = i + 1; j < total; ++j) {
if (drawCalls[j].verts != dc.verts)
break;
indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound);
indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound);
lastMatch = j;
}
// 2. Loop through the drawcalls, translating indices as we go.
switch (dc.indexType) {
case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT:
for (int j = i; j <= lastMatch; j++) {
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound);
}
break;
case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT:
for (int j = i; j <= lastMatch; j++) {
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16 *)drawCalls[j].inds, indexLowerBound);
}
break;
}
const int vertexCount = indexUpperBound - indexLowerBound + 1;
// This check is a workaround for Pangya Fantasy Golf, which sends bogus index data when switching items in "My Room" sometimes.
if (decodedVerts + vertexCount > VERTEX_BUFFER_MAX) {
return;
}
// 3. Decode that range of vertex data.
dec_->DecodeVerts(dest + decodedVerts * (int)dec_->GetDecVtxFmt().stride,
dc.verts, indexLowerBound, indexUpperBound);
decodedVerts += vertexCount;
// 4. Advance indexgen vertex counter.
indexGen.Advance(vertexCount);
i = lastMatch;
}
}
void DrawEngineVulkan::DecodeVerts(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf) { void DrawEngineVulkan::DecodeVerts(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf) {
int decodedVerts = 0; int decodedVerts = 0;
@ -343,69 +417,19 @@ void DrawEngineVulkan::DecodeVerts(VulkanPushBuffer *push, uint32_t *bindOffset,
dest = (u8 *)push->Push(vertsToDecode * dec_->GetDecVtxFmt().stride, bindOffset, vkbuf); dest = (u8 *)push->Push(vertsToDecode * dec_->GetDecVtxFmt().stride, bindOffset, vkbuf);
} }
for (int i = 0; i < numDrawCalls; i++) { if (uvScale) {
const DeferredDrawCall &dc = drawCalls[i]; const UVScale origUV = gstate_c.uv;
for (int i = 0; i < numDrawCalls; i++) {
indexGen.SetIndex(decodedVerts); gstate_c.uv = uvScale[i];
int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound; DecodeVertsStep(dest, i, decodedVerts); // Note that this can modify i
}
void *inds = dc.inds; gstate_c.uv = origUV;
if (dc.indexType == GE_VTYPE_IDX_NONE >> GE_VTYPE_IDX_SHIFT) { } else {
// Decode the verts and apply morphing. Simple. for (int i = 0; i < numDrawCalls; i++) {
dec_->DecodeVerts(dest + decodedVerts * (int)dec_->GetDecVtxFmt().stride, DecodeVertsStep(dest, i, decodedVerts); // Note that this can modify i
dc.verts, indexLowerBound, indexUpperBound);
decodedVerts += indexUpperBound - indexLowerBound + 1;
indexGen.AddPrim(dc.prim, dc.vertexCount);
} else {
// It's fairly common that games issue long sequences of PRIM calls, with differing
// inds pointer but the same base vertex pointer. We'd like to reuse vertices between
// these as much as possible, so we make sure here to combine as many as possible
// into one nice big drawcall, sharing data.
// 1. Look ahead to find the max index, only looking as "matching" drawcalls.
// Expand the lower and upper bounds as we go.
int lastMatch = i;
const int total = numDrawCalls;
for (int j = i + 1; j < total; ++j) {
if (drawCalls[j].verts != dc.verts)
break;
indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound);
indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound);
lastMatch = j;
}
// 2. Loop through the drawcalls, translating indices as we go.
switch (dc.indexType) {
case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT:
for (int j = i; j <= lastMatch; j++) {
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound);
}
break;
case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT:
for (int j = i; j <= lastMatch; j++) {
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16 *)drawCalls[j].inds, indexLowerBound);
}
break;
}
const int vertexCount = indexUpperBound - indexLowerBound + 1;
// This check is a workaround for Pangya Fantasy Golf, which sends bogus index data when switching items in "My Room" sometimes.
if (decodedVerts + vertexCount > VERTEX_BUFFER_MAX) {
return;
}
// 3. Decode that range of vertex data.
dec_->DecodeVerts(dest + decodedVerts * (int)dec_->GetDecVtxFmt().stride,
dc.verts, indexLowerBound, indexUpperBound);
decodedVerts += vertexCount;
// 4. Advance indexgen vertex counter.
indexGen.Advance(vertexCount);
i = lastMatch;
} }
} }
// Sanity check // Sanity check
if (indexGen.Prim() < 0) { if (indexGen.Prim() < 0) {
ERROR_LOG_REPORT(G3D, "DecodeVerts: Failed to deduce prim: %i", indexGen.Prim()); ERROR_LOG_REPORT(G3D, "DecodeVerts: Failed to deduce prim: %i", indexGen.Prim());

View file

@ -147,6 +147,8 @@ private:
struct FrameData; struct FrameData;
void DecodeVerts(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf); void DecodeVerts(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf);
void DecodeVertsStep(u8 *dest, int &i, int &decodedVerts);
void DoFlush(VkCommandBuffer cmd); void DoFlush(VkCommandBuffer cmd);
void UpdateUBOs(FrameData *frame); void UpdateUBOs(FrameData *frame);
@ -244,6 +246,7 @@ private:
DeferredDrawCall drawCalls[MAX_DEFERRED_DRAW_CALLS]; DeferredDrawCall drawCalls[MAX_DEFERRED_DRAW_CALLS];
int numDrawCalls; int numDrawCalls;
int vertexCountInDrawCalls; int vertexCountInDrawCalls;
UVScale *uvScale;
bool fboTexNeedBind_; bool fboTexNeedBind_;
bool fboTexBound_; bool fboTexBound_;

View file

@ -311,6 +311,9 @@ void GameSettingsScreen::CreateViews() {
CheckBox *depthWrite = graphicsSettings->Add(new CheckBox(&g_Config.bAlwaysDepthWrite, gr->T("Always Depth Write"))); CheckBox *depthWrite = graphicsSettings->Add(new CheckBox(&g_Config.bAlwaysDepthWrite, gr->T("Always Depth Write")));
depthWrite->SetDisabledPtr(&g_Config.bSoftwareRendering); depthWrite->SetDisabledPtr(&g_Config.bSoftwareRendering);
graphicsSettings->Add(new CheckBox(&g_Config.bPrescaleUV, gr->T("Texture Coord Speedhack")));
depthWrite->SetDisabledPtr(&g_Config.bSoftwareRendering);
static const char *bloomHackOptions[] = { "Off", "Safe", "Balanced", "Aggressive" }; static const char *bloomHackOptions[] = { "Off", "Safe", "Balanced", "Aggressive" };
PopupMultiChoice *bloomHack = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBloomHack, gr->T("Lower resolution for effects (reduces artifacts)"), bloomHackOptions, 0, ARRAY_SIZE(bloomHackOptions), gr->GetName(), screenManager())); PopupMultiChoice *bloomHack = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBloomHack, gr->T("Lower resolution for effects (reduces artifacts)"), bloomHackOptions, 0, ARRAY_SIZE(bloomHackOptions), gr->GetName(), screenManager()));
bloomHackEnable_ = !g_Config.bSoftwareRendering && (g_Config.iInternalResolution != 1); bloomHackEnable_ = !g_Config.bSoftwareRendering && (g_Config.iInternalResolution != 1);