From 14e9c9da80ff8470828617c6134331a12b144b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 10:29:01 +0100 Subject: [PATCH 01/24] Minor cleanup, fix a comment. --- GPU/Vulkan/DrawEngineVulkan.cpp | 14 +++++++------- GPU/Vulkan/DrawEngineVulkan.h | 2 +- ext/native/thin3d/VulkanRenderManager.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index de25539f92..7682e84e21 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -502,7 +502,7 @@ void DrawEngineVulkan::SetLineWidth(float lineWidth) { pipelineManager_->SetLineWidth(lineWidth); } -VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone) { +VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess) { DescriptorSetKey key; key.imageView_ = imageView; key.sampler_ = sampler; @@ -514,8 +514,6 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView _dbg_assert_(G3D, light != VK_NULL_HANDLE); _dbg_assert_(G3D, bone != VK_NULL_HANDLE); - bool tess = gstate_c.bezier || gstate_c.spline; - FrameData *frame = &frame_[vulkan_->GetCurFrame()]; // See if we already have this descriptor set cached. if (!tess) { // Don't cache descriptors for HW tessellation. @@ -627,7 +625,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView vkUpdateDescriptorSets(vulkan_->GetDevice(), n, writes, 0, nullptr); - if (!(gstate_c.bezier || gstate_c.spline)) // Avoid caching when HW tessellation. + if (!tess) // Again, avoid caching when HW tessellation. frame->descSets.Insert(key, desc); return desc; } @@ -667,6 +665,8 @@ void DrawEngineVulkan::DoFlush() { FrameData *frame = &frame_[vulkan_->GetCurFrame()]; + bool tess = gstate_c.bezier || gstate_c.spline; + bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); @@ -908,7 +908,7 @@ void DrawEngineVulkan::DoFlush() { dirtyUniforms_ |= shaderManager_->UpdateUniforms(); UpdateUBOs(frame); - VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf); + VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf, tess); { PROFILE_THIS_SCOPE("renderman_q"); @@ -921,7 +921,7 @@ void DrawEngineVulkan::DoFlush() { if (useElements) { if (!ibuf) ibOffset = (uint32_t)frame->pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf); - int numInstances = (gstate_c.bezier || gstate_c.spline) ? numPatches : 1; + int numInstances = tess ? numPatches : 1; renderManager->DrawIndexed(pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, numInstances, VK_INDEX_TYPE_UINT16); } else { renderManager->Draw(pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, vertexCount); @@ -1008,7 +1008,7 @@ void DrawEngineVulkan::DoFlush() { // Even if the first draw is through-mode, make sure we at least have one copy of these uniforms buffered UpdateUBOs(frame); - VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf); + VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf, tess); const uint32_t dynamicUBOOffsets[3] = { baseUBOOffset, lightUBOOffset, boneUBOOffset, }; diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 8c0bcff4c4..e00a4b37ef 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -193,7 +193,7 @@ private: void DoFlush(); void UpdateUBOs(FrameData *frame); - VkDescriptorSet GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone); + VkDescriptorSet GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess); VulkanContext *vulkan_; Draw::DrawContext *draw_; diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 4f265e8f81..d578ac7335 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -11,7 +11,7 @@ #define VLOG(...) #endif -// TODO: Using a thread here is unfinished and does not work correctly. +// This works great. Not much reason to disable so let's not even bother with an option. const bool useThread = true; #ifndef UINT64_MAX From 04e313ecba4ef0f55094be4977d6660fc288a1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 10:42:05 +0100 Subject: [PATCH 02/24] Unify Execute_Bezier and Execute_Spline --- GPU/D3D11/GPU_D3D11.cpp | 140 +------------------------------------ GPU/D3D11/GPU_D3D11.h | 2 - GPU/Directx9/GPU_DX9.cpp | 107 +---------------------------- GPU/Directx9/GPU_DX9.h | 2 - GPU/GLES/GPU_GLES.cpp | 141 +------------------------------------- GPU/GPUCommon.cpp | 50 +++++++++++++- GPU/Vulkan/GPU_Vulkan.cpp | 141 +------------------------------------- GPU/Vulkan/GPU_Vulkan.h | 2 - 8 files changed, 56 insertions(+), 529 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 3c402a2025..5ca54d603e 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -84,8 +84,8 @@ static const D3D11CommandTableEntry commandTable[] = { { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_D3D11::Execute_VertexType }, { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Prim }, - { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Bezier }, - { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Spline }, + { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier }, + { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline }, // 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 }, @@ -547,142 +547,6 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) { AdvanceVerts(vertexType, count, bytesRead); } -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); - - // This also make skipping drawing very effective. - framebufferManagerD3D11_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); - if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { - // TODO: Should this eat some cycles? Probably yes. Not sure if important. - return; - } - - if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); - return; - } - - void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *indices = NULL; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { - if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); - return; - } - indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); - } - - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); - } - - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim)); - - int bz_ucount = op & 0xFF; - int bz_vcount = (op >> 8) & 0xFF; - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; - - if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) { - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.bezier = true; - if (gstate_c.spline_count_u != bz_ucount) { - gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_count_u = bz_ucount; - } - } - - 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) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.bezier = false; - - // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = bz_ucount * bz_vcount; - AdvanceVerts(gstate.vertType, count, bytesRead); -} - -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); - - // This also make skipping drawing very effective. - framebufferManagerD3D11_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); - if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { - // TODO: Should this eat some cycles? Probably yes. Not sure if important. - return; - } - - if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); - return; - } - - void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *indices = NULL; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { - if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); - return; - } - indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); - } - - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); - } - - int sp_ucount = op & 0xFF; - int sp_vcount = (op >> 8) & 0xFF; - int sp_utype = (op >> 16) & 0x3; - int sp_vtype = (op >> 18) & 0x3; - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim)); - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; - u32 vertType = gstate.vertType; - - if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) { - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.spline = true; - bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount; - bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype; - if (countsChanged || typesChanged) { - gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_count_u = sp_ucount; - gstate_c.spline_count_v = sp_vcount; - gstate_c.spline_type_u = sp_utype; - gstate_c.spline_type_v = sp_vtype; - } - } - 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) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.spline = false; - - // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = sp_ucount * sp_vcount; - AdvanceVerts(gstate.vertType, count, bytesRead); -} - void GPU_D3D11::Execute_TexSize0(u32 op, u32 diff) { // Render to texture may have overridden the width/height. // Don't reset it unless the size is different / the texture has changed. diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index a528d41169..ecf36491ac 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -68,8 +68,6 @@ public: }; void Execute_Prim(u32 op, u32 diff); - void Execute_Bezier(u32 op, u32 diff); - void Execute_Spline(u32 op, u32 diff); void Execute_VertexType(u32 op, u32 diff); void Execute_VertexTypeSkinning(u32 op, u32 diff); void Execute_TexSize0(u32 op, u32 diff); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index bc85e33e0f..9d47ba66cc 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -68,8 +68,8 @@ static const D3D9CommandTableEntry commandTable[] = { { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_DX9::Execute_VertexType }, { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_DX9::Execute_Prim }, - { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_Bezier }, - { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_Spline }, + { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier }, + { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline }, // 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 }, @@ -511,109 +511,6 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) { AdvanceVerts(vertexType, count, bytesRead); } -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); - - // This also make skipping drawing very effective. - framebufferManagerDX9_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); - if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { - // TODO: Should this eat some cycles? Probably yes. Not sure if important. - return; - } - - if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); - return; - } - - void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *indices = NULL; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { - if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); - return; - } - indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); - } - - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); - } - - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim)); - int bz_ucount = op & 0xFF; - int bz_vcount = (op >> 8) & 0xFF; - 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. - int count = bz_ucount * bz_vcount; - AdvanceVerts(gstate.vertType, count, bytesRead); -} - -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); - - // This also make skipping drawing very effective. - framebufferManagerDX9_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); - if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { - // TODO: Should this eat some cycles? Probably yes. Not sure if important. - return; - } - - if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); - return; - } - - void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *indices = NULL; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { - if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); - return; - } - indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); - } - - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); - } - - int sp_ucount = op & 0xFF; - int sp_vcount = (op >> 8) & 0xFF; - int sp_utype = (op >> 16) & 0x3; - int sp_vtype = (op >> 18) & 0x3; - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim)); - bool computeNormals = gstate.isLightingEnabled(); - 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. - int count = sp_ucount * sp_vcount; - AdvanceVerts(gstate.vertType, count, bytesRead); -} - void GPU_DX9::Execute_TexSize0(u32 op, u32 diff) { // Render to texture may have overridden the width/height. // Don't reset it unless the size is different / the texture has changed. diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 2f15d48197..33753a59b6 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -69,8 +69,6 @@ public: }; void Execute_Prim(u32 op, u32 diff); - void Execute_Bezier(u32 op, u32 diff); - void Execute_Spline(u32 op, u32 diff); void Execute_VertexType(u32 op, u32 diff); void Execute_VertexTypeSkinning(u32 op, u32 diff); void Execute_TexSize0(u32 op, u32 diff); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 781f4c5cd7..64ae717b63 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -71,8 +71,8 @@ static const GLESCommandTableEntry commandTable[] = { { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_GLES::Execute_VertexType }, { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_GLES::Execute_Prim }, - { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_GLES::Execute_Bezier }, - { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_GLES::Execute_Spline }, + { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier }, + { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline }, // 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 }, @@ -719,143 +719,6 @@ void GPU_GLES::Execute_VertexTypeSkinning(u32 op, u32 diff) { gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); } -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); - - // This also make skipping drawing very effective. - framebufferManagerGL_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); - if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { - // TODO: Should this eat some cycles? Probably yes. Not sure if important. - return; - } - - if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); - return; - } - - void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *indices = NULL; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { - if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); - return; - } - indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); - } - - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); - } - - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim)); - - int bz_ucount = op & 0xFF; - int bz_vcount = (op >> 8) & 0xFF; - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; - - if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) { - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.bezier = true; - if (gstate_c.spline_count_u != bz_ucount) { - gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_count_u = bz_ucount; - } - } - - 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) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.bezier = false; - - // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = bz_ucount * bz_vcount; - AdvanceVerts(gstate.vertType, count, bytesRead); -} - -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); - - // This also make skipping drawing very effective. - framebufferManagerGL_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); - if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { - // TODO: Should this eat some cycles? Probably yes. Not sure if important. - return; - } - - if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); - return; - } - - void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *indices = NULL; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { - if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); - return; - } - indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); - } - - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); - } - - int sp_ucount = op & 0xFF; - int sp_vcount = (op >> 8) & 0xFF; - int sp_utype = (op >> 16) & 0x3; - int sp_vtype = (op >> 18) & 0x3; - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim)); - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; - u32 vertType = gstate.vertType; - - if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) { - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.spline = true; - bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount; - bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype; - if (countsChanged || typesChanged) { - gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_count_u = sp_ucount; - gstate_c.spline_count_v = sp_vcount; - gstate_c.spline_type_u = sp_utype; - gstate_c.spline_type_v = sp_vtype; - } - } - - 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) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.spline = false; - - // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = sp_ucount * sp_vcount; - AdvanceVerts(gstate.vertType, count, bytesRead); -} - void GPU_GLES::Execute_TexSize0(u32 op, u32 diff) { // Render to texture may have overridden the width/height. // Don't reset it unless the size is different / the texture has changed. diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 347b331244..d95a1a6a67 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1324,7 +1324,11 @@ void GPUCommon::Execute_TexLevel(u32 op, u32 diff) { } void GPUCommon::Execute_Bezier(u32 op, u32 diff) { - Flush(); + drawEngineCommon_->DispatchFlush(); + + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. + gstate_c.Dirty(DIRTY_UVSCALEOFFSET); + // 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)) { @@ -1355,20 +1359,41 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) { } GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); + SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim)); + int bz_ucount = op & 0xFF; int bz_vcount = (op >> 8) & 0xFF; bool computeNormals = gstate.isLightingEnabled(); bool patchFacing = gstate.patchfacing & 1; + + if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) { + gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); + gstate_c.bezier = true; + if (gstate_c.spline_count_u != bz_ucount) { + gstate_c.Dirty(DIRTY_BEZIERSPLINE); + gstate_c.spline_count_u = bz_ucount; + } + } + int bytesRead = 0; + UpdateUVScaleOffset(); drawEngineCommon_->SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); + if (gstate_c.bezier) + gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); + gstate_c.bezier = false; + // After drawing, we advance pointers - see SubmitPrim which does the same. int count = bz_ucount * bz_vcount; AdvanceVerts(gstate.vertType, count, bytesRead); } void GPUCommon::Execute_Spline(u32 op, u32 diff) { - Flush(); + drawEngineCommon_->DispatchFlush(); + + // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier. + gstate_c.Dirty(DIRTY_UVSCALEOFFSET); + // 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)) { @@ -1403,12 +1428,33 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) { int sp_utype = (op >> 16) & 0x3; int sp_vtype = (op >> 18) & 0x3; GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); + SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim)); bool computeNormals = gstate.isLightingEnabled(); bool patchFacing = gstate.patchfacing & 1; u32 vertType = gstate.vertType; + + if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) { + gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); + gstate_c.spline = true; + bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount; + bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype; + if (countsChanged || typesChanged) { + gstate_c.Dirty(DIRTY_BEZIERSPLINE); + gstate_c.spline_count_u = sp_ucount; + gstate_c.spline_count_v = sp_vcount; + gstate_c.spline_type_u = sp_utype; + gstate_c.spline_type_v = sp_vtype; + } + } + int bytesRead = 0; + UpdateUVScaleOffset(); drawEngineCommon_->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) + gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); + gstate_c.spline = false; + // After drawing, we advance pointers - see SubmitPrim which does the same. int count = sp_ucount * sp_vcount; AdvanceVerts(gstate.vertType, count, bytesRead); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 1aba78d76f..75e7faac1a 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -66,8 +66,8 @@ static const VulkanCommandTableEntry commandTable[] = { { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_Vulkan::Execute_VertexType }, { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_Prim }, - { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_Bezier }, - { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_Spline }, + { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier }, + { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline }, // 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 }, @@ -586,143 +586,6 @@ void GPU_Vulkan::Execute_VertexTypeSkinning(u32 op, u32 diff) { gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); } -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); - - // 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)) { - // TODO: Should this eat some cycles? Probably yes. Not sure if important. - return; - } - - if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); - return; - } - - void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *indices = NULL; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { - if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); - return; - } - indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); - } - - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); - } - - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim)); - - int bz_ucount = op & 0xFF; - int bz_vcount = (op >> 8) & 0xFF; - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; - - if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) { - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.bezier = true; - if (gstate_c.spline_count_u != bz_ucount) { - gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_count_u = bz_ucount; - } - } - - 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) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.bezier = false; - - // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = bz_ucount * bz_vcount; - AdvanceVerts(gstate.vertType, count, bytesRead); -} - -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); - - // 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)) { - // TODO: Should this eat some cycles? Probably yes. Not sure if important. - return; - } - - if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); - return; - } - - void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); - void *indices = NULL; - if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { - if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); - return; - } - indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); - } - - if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { - DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); - } - if (vertTypeIsSkinningEnabled(gstate.vertType)) { - DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); - } - - int sp_ucount = op & 0xFF; - int sp_vcount = (op >> 8) & 0xFF; - int sp_utype = (op >> 16) & 0x3; - int sp_vtype = (op >> 18) & 0x3; - GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); - SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim)); - bool computeNormals = gstate.isLightingEnabled(); - bool patchFacing = gstate.patchfacing & 1; - u32 vertType = gstate.vertType; - - if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) { - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.spline = true; - bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount; - bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype; - if (countsChanged || typesChanged) { - gstate_c.Dirty(DIRTY_BEZIERSPLINE); - gstate_c.spline_count_u = sp_ucount; - gstate_c.spline_count_v = sp_vcount; - gstate_c.spline_type_u = sp_utype; - gstate_c.spline_type_v = sp_vtype; - } - } - - 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) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - gstate_c.spline = false; - - // After drawing, we advance pointers - see SubmitPrim which does the same. - int count = sp_ucount * sp_vcount; - AdvanceVerts(gstate.vertType, count, bytesRead); -} - void GPU_Vulkan::Execute_TexSize0(u32 op, u32 diff) { // Render to texture may have overridden the width/height. // Don't reset it unless the size is different / the texture has changed. diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index d94c4ee768..962f6601a0 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -72,8 +72,6 @@ public: }; void Execute_Prim(u32 op, u32 diff); - void Execute_Bezier(u32 op, u32 diff); - void Execute_Spline(u32 op, u32 diff); void Execute_VertexType(u32 op, u32 diff); void Execute_VertexTypeSkinning(u32 op, u32 diff); void Execute_TexSize0(u32 op, u32 diff); From 0f100142191c57a24c17c7a8095b2e114035ff9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 11:13:38 +0100 Subject: [PATCH 03/24] DevScreens: In shader viewer tabs, show the number of each shader type. --- UI/DevScreens.cpp | 9 ++++++--- UI/DevScreens.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index c43039a5e2..2344342262 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -899,14 +899,17 @@ UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) { return UI::EVENT_DONE; } -void ShaderListScreen::ListShaders(DebugShaderType shaderType, UI::LinearLayout *view) { +int ShaderListScreen::ListShaders(DebugShaderType shaderType, UI::LinearLayout *view) { using namespace UI; std::vector shaderIds_ = gpu->DebugGetShaderIDs(shaderType); + int count = 0; for (auto id : shaderIds_) { Choice *choice = view->Add(new Choice(gpu->DebugGetShaderString(id, shaderType, SHADER_STRING_SHORT_DESC))); choice->SetTag(id); choice->OnClick.Handle(this, &ShaderListScreen::OnShaderClick); + count++; } + return count; } struct { DebugShaderType type; const char *name; } shaderTypes[] = { @@ -933,9 +936,9 @@ void ShaderListScreen::CreateViews() { for (size_t i = 0; i < ARRAY_SIZE(shaderTypes); i++) { ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0)); LinearLayout *shaderList = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT)); - ListShaders(shaderTypes[i].type, shaderList); + int count = ListShaders(shaderTypes[i].type, shaderList); scroll->Add(shaderList); - tabs_->AddTab(shaderTypes[i].name, scroll); + tabs_->AddTab(StringFromFormat("%s (%d)", shaderTypes[i].name, count), scroll); } } diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 91cfde222f..6c37850c8b 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -152,7 +152,7 @@ public: void CreateViews() override; private: - void ListShaders(DebugShaderType shaderType, UI::LinearLayout *view); + int ListShaders(DebugShaderType shaderType, UI::LinearLayout *view); UI::EventReturn OnShaderClick(UI::EventParams &e); From 3e749a94ce5085cccb5b7cbae57f35f813fb4e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 11:16:20 +0100 Subject: [PATCH 04/24] Vulkan: Fix bug where we ended up creating duplicate pipelines even if vertices decoded to the same format, if they were created from different formats. This can cut down the number of pipelines to a third or less in some games. However, benefit is likely smaller since Vulkan drivers will deduplicate shaders inside each vkPipelineCache object. Helps #10106 while not actually implementing any of the suggestions inside. --- GPU/Common/VertexDecoderCommon.cpp | 8 ++++++-- GPU/Common/VertexDecoderCommon.h | 21 ++++----------------- GPU/D3D11/DrawEngineD3D11.cpp | 2 -- GPU/Directx9/DrawEngineDX9.cpp | 3 --- GPU/GLES/DrawEngineGLES.cpp | 2 -- GPU/Vulkan/DrawEngineVulkan.cpp | 4 ++-- GPU/Vulkan/PipelineManagerVulkan.cpp | 17 +++++++---------- GPU/Vulkan/PipelineManagerVulkan.h | 4 ++-- 8 files changed, 21 insertions(+), 40 deletions(-) diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 5ddcc18347..4cd6f9e40d 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -73,13 +73,15 @@ int DecFmtSize(u8 fmt) { case DEC_U16_2: return 4; case DEC_U16_3: return 8; case DEC_U16_4: return 8; - case DEC_U8A_2: return 4; - case DEC_U16A_2: return 4; default: return 0; } } +void DecVtxFormat::ComputeID() { + id = w0fmt | (w1fmt << 4) | (uvfmt << 8) | (c0fmt << 12) | (c1fmt << 16) | (nrmfmt << 20) | (posfmt << 24); +} + void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound) { // Find index bounds. Could cache this in display lists. // Also, this could be greatly sped up with SSE2/NEON, although rarely a bottleneck. @@ -1152,6 +1154,8 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, decFmt.stride = decOff; + decFmt.ComputeID(); + size = align(size, biggest); onesize_ = size; size *= morphcount; diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 9222090480..fbe60c1756 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -43,6 +43,7 @@ // Can write code to easily bind these using OpenGL, or read these manually. // No morph support, that is taken care of by the VertexDecoder. +// Keep this in 4 bits. enum { DEC_NONE, DEC_FLOAT_1, @@ -59,8 +60,6 @@ enum { DEC_U16_2, DEC_U16_3, DEC_U16_4, - DEC_U8A_2, - DEC_U16A_2, }; int DecFmtSize(u8 fmt); @@ -74,6 +73,9 @@ struct DecVtxFormat { u8 nrmfmt; u8 nrmoff; u8 posfmt; u8 posoff; short stride; + + uint32_t id; + void ComputeID(); }; struct TransformedVertex @@ -297,21 +299,6 @@ public: } break; - case DEC_U8A_2: - { - const u8 *b = (const u8 *)(data_ + decFmt_.uvoff); - uv[0] = (float)b[0]; - uv[1] = (float)b[1]; - } - break; - - case DEC_U16A_2: - { - const u16 *p = (const u16 *)(data_ + decFmt_.uvoff); - uv[0] = (float)p[0]; - uv[1] = (float)p[1]; - } - break; default: ERROR_LOG_REPORT_ONCE(fmtuv, G3D, "Reader: Unsupported UV Format %d", decFmt_.uvfmt); memset(uv, 0, sizeof(float) * 2); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index e8e6ba8580..1a3ad5f9c2 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -175,8 +175,6 @@ static const DeclTypeInfo VComp[] = { { DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16_2" }, // DEC_U16_2, { DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3, { DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4, - { DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U8A_2"}, // DEC_U8A_2, - { DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16A_2" }, // DEC_U16A_2, }; static void VertexAttribSetup(D3D11_INPUT_ELEMENT_DESC * VertexElement, u8 fmt, u8 offset, const char *semantic, u8 semantic_index = 0) { diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 68d5d837fb..f452c945c0 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -155,9 +155,6 @@ static const DeclTypeInfo VComp[] = { {0, "UNUSED_DEC_U16_2" }, // DEC_U16_2, {D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3, {D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4, - // Not supported in regular DX9 so faking, will cause graphics bugs until worked around - {0,"UNUSED_DEC_U8A_2"}, // DEC_U8A_2, - {0,"UNUSED_DEC_U16A_2" }, // DEC_U16A_2, }; static void VertexAttribSetup(D3DVERTEXELEMENT9 * VertexElement, u8 fmt, u8 offset, u8 usage, u8 usage_index = 0) { diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index fe1f1e0653..6034d491c3 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -228,8 +228,6 @@ static const GlTypeInfo GLComp[] = { {GL_UNSIGNED_SHORT, 2, GL_TRUE},// DEC_U16_2, {GL_UNSIGNED_SHORT, 3, GL_TRUE},// DEC_U16_3, {GL_UNSIGNED_SHORT, 4, GL_TRUE},// DEC_U16_4, - {GL_UNSIGNED_BYTE, 2, GL_FALSE},// DEC_U8A_2, - {GL_UNSIGNED_SHORT, 2, GL_FALSE},// DEC_U16A_2, }; static inline void VertexAttribSetup(int attrib, int fmt, int stride, u8 *ptr) { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 7682e84e21..addf18655e 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -887,7 +887,7 @@ void DrawEngineVulkan::DoFlush() { } Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, true); if (!pipeline) { // Already logged, let's bail out. return; @@ -985,7 +985,7 @@ void DrawEngineVulkan::DoFlush() { } Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false); + VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, false); if (!pipeline) { // Already logged, let's bail out. return; diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 940254e7d1..928a4398b9 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -66,9 +66,6 @@ static const DeclTypeInfo VComp[] = { { VK_FORMAT_R16G16_UNORM, "R16G16_UNORM" }, // DEC_U16_2, { VK_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16_UNORM " }, // DEC_U16_3, { VK_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16_UNORM " }, // DEC_U16_4, - - { VK_FORMAT_R8G8_UINT, "R8G8_UINT" }, // DEC_U8A_2, - { VK_FORMAT_R16G16_UINT, "R16G16_UINT" }, // DEC_U16A_2, }; static void VertexAttribSetup(VkVertexInputAttributeDescription *attr, int fmt, int offset, PspAttributeLocation location) { @@ -121,7 +118,7 @@ static bool UsesBlendConstant(int factor) { static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pipelineCache, VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &key, - const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, float lineWidth) { + const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, float lineWidth) { bool useBlendConstant = false; VkPipelineColorBlendAttachmentState blend0 = {}; @@ -229,10 +226,10 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip VkVertexInputAttributeDescription attrs[8]; int attributeCount; if (useHwTransform) { - attributeCount = SetupVertexAttribs(attrs, vtxDec->decFmt); - vertexStride = vtxDec->decFmt.stride; + attributeCount = SetupVertexAttribs(attrs, *decFmt); + vertexStride = decFmt->stride; } else { - attributeCount = SetupVertexAttribsPretransformed(attrs, vtxDec->decFmt); + attributeCount = SetupVertexAttribsPretransformed(attrs, *decFmt); vertexStride = 36; } @@ -301,7 +298,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip return vulkanPipeline; } -VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) { +VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) { VulkanPipelineKey key; if (!renderPass) Crash(); @@ -311,7 +308,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo key.useHWTransform = useHwTransform; key.vShader = vs->GetModule(); key.fShader = fs->GetModule(); - key.vtxDec = useHwTransform ? vtxDec : nullptr; + key.vtxDecId = useHwTransform ? decFmt->id : 0; auto iter = pipelines_.Get(key); if (iter) @@ -321,7 +318,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo VulkanPipeline *pipeline = CreateVulkanPipeline( vulkan_->GetDevice(), pipelineCache_, layout, renderPass, - rasterKey, vtxDec, vs, fs, useHwTransform, lineWidth_); + rasterKey, decFmt, vs, fs, useHwTransform, lineWidth_); // Even if the result is nullptr, insert it so we don't try to create it repeatedly. pipelines_.Insert(key, pipeline); return pipeline; diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 9387ed43fe..1099278be6 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -41,7 +41,7 @@ struct VulkanPipelineKey { VulkanPipelineRasterStateKey raster; // prim is included here VkRenderPass renderPass; bool useHWTransform; - const VertexDecoder *vtxDec; + uint32_t vtxDecId; VkShaderModule vShader; VkShaderModule fShader; @@ -77,7 +77,7 @@ public: PipelineManagerVulkan(VulkanContext *ctx); ~PipelineManagerVulkan(); - VulkanPipeline *GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform); + VulkanPipeline *GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform); int GetNumPipelines() const { return (int)pipelines_.size(); } void Clear(); From 4a09289056d435ecd030b2027a60895313da6196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 12:26:52 +0100 Subject: [PATCH 05/24] D3D11: Similarly to the last vulkan commit, don't create lots of dupe vertex input layouts --- GPU/D3D11/DrawEngineD3D11.cpp | 2 +- GPU/D3D11/DrawEngineD3D11.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 1a3ad5f9c2..1920b78269 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -188,7 +188,7 @@ static void VertexAttribSetup(D3D11_INPUT_ELEMENT_DESC * VertexElement, u8 fmt, ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshader, const DecVtxFormat &decFmt, u32 pspFmt) { // TODO: Instead of one for each vshader, we can reduce it to one for each type of shader // that reads TEXCOORD or not, etc. Not sure if worth it. - InputLayoutKey key{ vshader, pspFmt }; + InputLayoutKey key{ vshader, decFmt.id }; ID3D11InputLayout *inputLayout = inputLayoutMap_.Get(key); if (inputLayout) { return inputLayout; diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 7838c79cea..5376bf15d3 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -170,11 +170,11 @@ private: struct InputLayoutKey { D3D11VertexShader *vshader; - u32 vertType; + u32 decFmtId; bool operator <(const InputLayoutKey &other) const { - if (vertType < other.vertType) + if (decFmtId < other.decFmtId) return true; - if (vertType > other.vertType) + if (decFmtId > other.decFmtId) return false; return vshader < other.vshader; } From 5c7f7c1df647f91b3f5f2fc1520ac15d9856b333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 15:18:27 +0100 Subject: [PATCH 06/24] Vulkan: Make sure to clear the pipeline key to avoid padding bytes causing us to allocate duplicate pipelines. Also pack the struct better. --- GPU/Vulkan/PipelineManagerVulkan.cpp | 2 +- GPU/Vulkan/PipelineManagerVulkan.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 928a4398b9..0f08616b1e 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -299,7 +299,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip } VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) { - VulkanPipelineKey key; + VulkanPipelineKey key{}; if (!renderPass) Crash(); diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 1099278be6..8463033784 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -40,10 +40,10 @@ enum class PspAttributeLocation { struct VulkanPipelineKey { VulkanPipelineRasterStateKey raster; // prim is included here VkRenderPass renderPass; - bool useHWTransform; - uint32_t vtxDecId; VkShaderModule vShader; VkShaderModule fShader; + uint32_t vtxDecId; + bool useHWTransform; void ToString(std::string *str) const { str->resize(sizeof(*this)); From 47882212519488c4cae276c8f4e4bd491e880d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 15:27:06 +0100 Subject: [PATCH 07/24] Vulkan shader view (debug): Add a simple textural representation (incomplete) of pipelines --- GPU/Vulkan/PipelineManagerVulkan.cpp | 126 +++++++++++++++++++++++++-- UI/DevScreens.cpp | 2 + 2 files changed, 123 insertions(+), 5 deletions(-) diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 0f08616b1e..f63f0de9c1 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -342,14 +342,75 @@ std::vector PipelineManagerVulkan::DebugGetObjectIDs(DebugShaderTyp return ids; } +static const char *const topologies[8] = { + "POINTLIST", + "LINELIST", + "LINESTRIP", + "TRILIST", + "TRISTRIP", + "TRIFAN", +}; + +static const char *const blendOps[8] = { + "ADD", + "SUB", + "REVSUB", + "MIN", + "MAX", +}; + +static const char *const compareOps[8] = { + "NEVER", + "<", + "==", + "<=", + ">", + ">=", + "!=", + "ALWAYS", +}; + +static const char *const stencilOps[8] = { + "KEEP", + "ZERO", + "REPLACE", + "INC_CLAMP", + "DEC_CLAMP", + "INVERT", + "INC_WRAP", + "DEC_WRAP", +}; + +static const char *const blendFactors[19] = { + "ZERO", + "ONE", + "SRC_COLOR", + "ONE_MINUS_SRC_COLOR", + "DST_COLOR", + "ONE_MINUS_DST_COLOR", + "SRC_ALPHA", + "ONE_MINUS_SRC_ALPHA", + "DST_ALPHA", + "ONE_MINUS_DST_ALPHA", + "CONSTANT_COLOR", + "ONE_MINUS_CONSTANT_COLOR", + "CONSTANT_ALPHA", + "ONE_MINUS_CONSTANT_ALPHA", + "SRC_ALPHA_SATURATE", + "SRC1_COLOR", + "ONE_MINUS_SRC1_COLOR", + "SRC1_ALPHA", + "ONE_MINUS_SRC1_ALPHA", +}; + std::string PipelineManagerVulkan::DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType) { if (type != SHADER_TYPE_PIPELINE) return "N/A"; - VulkanPipelineKey shaderId; - shaderId.FromString(id); + VulkanPipelineKey pipelineKey; + pipelineKey.FromString(id); - VulkanPipeline *iter = pipelines_.Get(shaderId); + VulkanPipeline *iter = pipelines_.Get(pipelineKey); if (!iter) { return ""; } @@ -357,7 +418,62 @@ std::string PipelineManagerVulkan::DebugGetObjectString(std::string id, DebugSha switch (stringType) { case SHADER_STRING_SHORT_DESC: { - return StringFromFormat("%p", iter); + std::stringstream str; + str << topologies[pipelineKey.raster.topology] << " "; + if (pipelineKey.raster.blendEnable) { + str << "Blend("; + str << "C:" << blendOps[pipelineKey.raster.blendOpColor] << "/" + << blendFactors[pipelineKey.raster.srcColor] << ":" << blendFactors[pipelineKey.raster.destColor] << " "; + if (pipelineKey.raster.blendOpAlpha != VK_BLEND_OP_ADD || + pipelineKey.raster.srcAlpha != VK_BLEND_FACTOR_ONE || + pipelineKey.raster.destAlpha != VK_BLEND_FACTOR_ZERO) { + str << "A:" << blendOps[pipelineKey.raster.blendOpAlpha] << "/" + << blendFactors[pipelineKey.raster.srcColor] << ":" << blendFactors[pipelineKey.raster.destColor] << " "; + } + str << ") "; + } + if (pipelineKey.raster.colorWriteMask != 0xF) { + str << "Mask("; + for (int i = 0; i < 4; i++) { + if (pipelineKey.raster.colorWriteMask & (1 << i)) { + str << "RGBA"[i]; + } else { + str << "_"; + } + } + str << ") "; + } + if (pipelineKey.raster.depthTestEnable) { + str << "Depth("; + if (pipelineKey.raster.depthWriteEnable) + str << "W, "; + if (pipelineKey.raster.depthCompareOp) + str << compareOps[pipelineKey.raster.depthCompareOp & 7]; + str << ") "; + } + if (pipelineKey.raster.stencilTestEnable) { + str << "Stencil("; + str << compareOps[pipelineKey.raster.stencilCompareOp & 7] << " "; + str << stencilOps[pipelineKey.raster.stencilPassOp & 7] << "/"; + str << stencilOps[pipelineKey.raster.stencilFailOp & 7] << "/"; + str << stencilOps[pipelineKey.raster.stencilDepthFailOp& 7]; + str << ") "; + } + if (pipelineKey.raster.logicOpEnable) { + str << "Logic("; + str << ") "; + } + if (pipelineKey.useHWTransform) { + str << "HWX "; + } + if (pipelineKey.vtxDecId) { + str << "V("; + str << StringFromFormat("%08x", pipelineKey.vtxDecId); // TODO: Format nicer. + str << ") "; + } else { + str << "SWX "; + } + return StringFromFormat("%p: %s", iter, str.str().c_str()); } case SHADER_STRING_SOURCE_CODE: @@ -382,4 +498,4 @@ void PipelineManagerVulkan::SetLineWidth(float lineWidth) { pipelines_.Remove(key); } }); -} \ No newline at end of file +} diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 2344342262..dfd6e9e876 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -399,7 +399,9 @@ void SystemInfoScreen::CreateViews() { deviceSpecs->Add(new ItemHeader("OS Information")); deviceSpecs->Add(new InfoItem("Memory Page Size", StringFromFormat("%d bytes", GetMemoryProtectPageSize()))); deviceSpecs->Add(new InfoItem("RW/RX exclusive: ", PlatformIsWXExclusive() ? "Yes" : "No")); +#ifdef ANDROID deviceSpecs->Add(new InfoItem("Sustained perf mode: ", System_GetPropertyBool(SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE) ? "Yes" : "No")); +#endif const char *build = "Release"; #ifdef _DEBUG From 8bfdf7b1b2f5bbc3093890b64ee1d67fe136d6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 15:45:31 +0100 Subject: [PATCH 08/24] Fix annoying little flicker when starting a game. --- UI/EmuScreen.cpp | 4 +++- UI/EmuScreen.h | 1 + ext/native/thin3d/VulkanRenderManager.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 1188e2fed2..54947cdb11 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -320,11 +320,13 @@ void EmuScreen::sendMessage(const char *message, const char *value) { // We will push MainScreen in update(). PSP_Shutdown(); bootPending_ = false; + stopRender_ = true; invalid_ = true; host->UpdateDisassembly(); } else if (!strcmp(message, "reset")) { PSP_Shutdown(); bootPending_ = true; + stopRender_ = true; invalid_ = true; host->UpdateDisassembly(); @@ -987,7 +989,7 @@ void EmuScreen::postRender() { Draw::DrawContext *draw = screenManager()->getDrawContext(); if (!draw) return; - if (invalid_) + if (stopRender_) draw->WipeQueue(); draw->EndFrame(); } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 3f103513b7..8fefb5226c 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -77,6 +77,7 @@ private: // Something invalid was loaded, don't try to emulate bool invalid_; bool quit_; + bool stopRender_ = false; std::string errorMessage_; // If set, pauses at the end of the frame. diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index d578ac7335..36ca452f21 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -227,6 +227,9 @@ void VulkanRenderManager::StopThread() { Crash(); } frameData.readyForRun = false; + for (size_t i = 0; i < frameData.steps.size(); i++) { + delete frameData.steps[i]; + } frameData.steps.clear(); std::unique_lock lock(frameData.push_mutex); @@ -803,8 +806,7 @@ void VulkanRenderManager::EndSubmitFrame(int frame) { present.waitSemaphoreCount = 1; VkResult res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present); - // TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI - // return codes + // TODO: Deal with VK_SUBOPTIMAL_WSI ? if (res == VK_ERROR_OUT_OF_DATE_KHR) { // ignore, it'll be fine. this happens sometimes during resizes, and we do make sure to recreate the swap chain. } else { From 22610295364ad6b9e79031bccc5339597306e92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 15:57:59 +0100 Subject: [PATCH 09/24] Delete unused duplicate functions --- GPU/Vulkan/GPU_Vulkan.cpp | 58 --------------------------------------- GPU/Vulkan/GPU_Vulkan.h | 3 -- 2 files changed, 61 deletions(-) diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 75e7faac1a..520f60fca1 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -602,64 +602,6 @@ void GPU_Vulkan::Execute_LoadClut(u32 op, u32 diff) { textureCacheVulkan_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes()); } -void GPU_Vulkan::Execute_BoneMtxNum(u32 op, u32 diff) { - // This is almost always followed by GE_CMD_BONEMATRIXDATA. - const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4); - u32 *dst = (u32 *)(gstate.boneMatrix + (op & 0x7F)); - const int end = 12 * 8 - (op & 0x7F); - int i = 0; - - // If we can't use software skinning, we have to flush and dirty. - while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) { - const u32 newVal = src[i] << 8; - if (dst[i] != newVal) { - Flush(); - dst[i] = newVal; - } - if (++i >= end) { - break; - } - } - - const int numPlusCount = (op & 0x7F) + i; - for (int num = op & 0x7F; num < numPlusCount; num += 12) { - gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12)); - } - - const int count = i; - gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | ((op + count) & 0x7F); - - // Skip over the loaded data, it's done now. - UpdatePC(currentList->pc, currentList->pc + count * 4); - currentList->pc += count * 4; -} - -void GPU_Vulkan::Execute_BoneMtxData(u32 op, u32 diff) { - // Note: it's uncommon to get here now, see above. - int num = gstate.boneMatrixNumber & 0x7F; - u32 newVal = op << 8; - if (num < 96 && newVal != ((const u32 *)gstate.boneMatrix)[num]) { - // Bone matrices should NOT flush when software skinning is enabled! - Flush(); - gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12)); - ((u32 *)gstate.boneMatrix)[num] = newVal; - } - num++; - gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (num & 0x7F); -} - -void GPU_Vulkan::FastLoadBoneMatrix(u32 target) { - const int num = gstate.boneMatrixNumber & 0x7F; - const int mtxNum = num / 12; - uint32_t uniformsToDirty = DIRTY_BONEMATRIX0 << mtxNum; - if ((num - 12 * mtxNum) != 0) { - uniformsToDirty |= DIRTY_BONEMATRIX0 << ((mtxNum + 1) & 7); - } - Flush(); - gstate_c.Dirty(uniformsToDirty); - gstate.FastLoadBoneMatrix(target); -} - void GPU_Vulkan::InitDeviceObjects() { ILOG("GPU_Vulkan::InitDeviceObjects"); // Initialize framedata diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 962f6601a0..f72ab93cc5 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -76,8 +76,6 @@ public: void Execute_VertexTypeSkinning(u32 op, u32 diff); void Execute_TexSize0(u32 op, u32 diff); void Execute_LoadClut(u32 op, u32 diff); - void Execute_BoneMtxNum(u32 op, u32 diff); - void Execute_BoneMtxData(u32 op, u32 diff); // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; @@ -85,7 +83,6 @@ public: protected: void FastRunLoop(DisplayList &list) override; - void FastLoadBoneMatrix(u32 target) override; void FinishDeferred() override; private: From 230f72a110b65fc75137ea92fa8689de1b264b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 16:38:35 +0100 Subject: [PATCH 10/24] Oops --- UI/EmuScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 54947cdb11..fc089d3c3c 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -326,13 +326,13 @@ void EmuScreen::sendMessage(const char *message, const char *value) { } else if (!strcmp(message, "reset")) { PSP_Shutdown(); bootPending_ = true; - stopRender_ = true; invalid_ = true; host->UpdateDisassembly(); std::string resetError; if (!PSP_InitStart(PSP_CoreParameter(), &resetError)) { ELOG("Error resetting: %s", resetError.c_str()); + stopRender_ = true; screenManager()->switchScreen(new MainScreen()); System_SendMessage("event", "failstartgame"); return; From 35437e6b627ae6bb794f6972c0270f979b0f4873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 16:50:45 +0100 Subject: [PATCH 11/24] Kill off more unused duplicate code --- GPU/D3D11/DrawEngineD3D11.cpp | 18 +----------------- GPU/D3D11/DrawEngineD3D11.h | 3 --- GPU/Vulkan/DrawEngineVulkan.cpp | 20 +------------------- GPU/Vulkan/DrawEngineVulkan.h | 3 --- 4 files changed, 2 insertions(+), 42 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 1920b78269..15d67838ee 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -249,22 +249,6 @@ ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshade } } -void DrawEngineD3D11::SetupVertexDecoder(u32 vertType) { - SetupVertexDecoderInternal(vertType); -} - -inline void DrawEngineD3D11::SetupVertexDecoderInternal(u32 vertType) { - // As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it - // into the top of the verttype where there are unused bits. - const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24); - - // If vtype has changed, setup the vertex decoder. - if (vertTypeID != lastVType_) { - dec_ = GetVertexDecoder(vertTypeID); - lastVType_ = vertTypeID; - } -} - void DrawEngineD3D11::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) { if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX) Flush(); @@ -276,7 +260,7 @@ void DrawEngineD3D11::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, prevPrim_ = prim; } - SetupVertexDecoderInternal(vertType); + SetupVertexDecoder(vertType); *bytesRead = vertexCount * dec_->VertexSize(); diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 5376bf15d3..b0c77b3e4b 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -121,9 +121,6 @@ public: void BeginFrame(); - void SetupVertexDecoder(u32 vertType); - void SetupVertexDecoderInternal(u32 vertType); - // So that this can be inlined void Flush() { if (!numDrawCalls) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index addf18655e..180d747d1a 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -361,24 +361,6 @@ void DrawEngineVulkan::EndFrame() { vertexCache_->End(); } -void DrawEngineVulkan::SetupVertexDecoder(u32 vertType) { - SetupVertexDecoderInternal(vertType); -} - -inline void DrawEngineVulkan::SetupVertexDecoderInternal(u32 vertType) { - // As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it - // into the top of the verttype where there are unused bits. - const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24); - - // If vtype has changed, setup the vertex decoder. - if (vertTypeID != lastVType_) { - dec_ = GetVertexDecoder(vertTypeID); - lastVType_ = vertTypeID; - } - if (!dec_) - Crash(); -} - void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) { if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX) Flush(); @@ -390,7 +372,7 @@ void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, prevPrim_ = prim; } - SetupVertexDecoderInternal(vertType); + SetupVertexDecoder(vertType); *bytesRead = vertexCount * dec_->VertexSize(); if ((vertexCount < 2 && prim > 0) || (vertexCount < 3 && prim > 2 && prim != GE_PRIM_RECTANGLES)) diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index e00a4b37ef..b9709f261f 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -140,9 +140,6 @@ public: void DeviceLost(); void DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw); - void SetupVertexDecoder(u32 vertType); - void SetupVertexDecoderInternal(u32 vertType); - // So that this can be inlined void Flush() { if (!numDrawCalls) From a0f1276a5c584180c494a51066d9d76b26f5503f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 17:18:12 +0100 Subject: [PATCH 12/24] Vulkan: Use optimal alignment for texture uploads. May help stutter in #10105 ? --- GPU/Vulkan/TextureCacheVulkan.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index b96eaec3f3..b4e9dc8e60 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -662,7 +662,9 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm int size = stride * mipHeight; uint32_t bufferOffset; VkBuffer texBuf; - void *data = drawEngine_->GetPushBufferForTextureData()->Push(size, &bufferOffset, &texBuf); + // nvidia returns 1 but that can't be healthy... let's align by 16 as a minimum. + int pushAlignment = std::max(16, (int)vulkan_->GetPhysicalDeviceProperties().limits.optimalBufferCopyOffsetAlignment); + void *data = drawEngine_->GetPushBufferForTextureData()->PushAligned(size, &bufferOffset, &texBuf, pushAlignment); if (replaced.Valid()) { replaced.Load(i, data, stride); } else { From 2c27b3b56bc28c15bbc28576dfea67c19e390464 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 02:35:14 +0100 Subject: [PATCH 13/24] Fix texture conversion. --- GPU/Common/TextureCacheCommon.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 2186529b44..1532806b33 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1190,18 +1190,11 @@ void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureForm memcpy(out + outPitch * y, texptr + bufw * sizeof(u16) * y, w * sizeof(u16)); } } - } else if (h >= 8) { + } else if (h >= 8 && !expandTo32bit) { // Note: this is always safe since h must be a power of 2, so a multiple of 8. - if (!expandTo32bit) { - UnswizzleFromMem((u32 *)out, outPitch, texptr, bufw, h, 2); - if (reverseColors) { - ReverseColors(out, out, format, h * outPitch / 2, useBGRA); - } - } else if (expandTo32bit) { - UnswizzleFromMem((u32 *)out, outPitch / 2, texptr, bufw, h, 2); - for (int y = h - 1; y >= 0; --y) { - ConvertFormatToRGBA8888(format, (u32 *)(out + outPitch * y), (const u16 *)(out + outPitch / 2 * y), w); - } + UnswizzleFromMem((u32 *)out, outPitch, texptr, bufw, h, 2); + if (reverseColors) { + ReverseColors(out, out, format, h * outPitch / 2, useBGRA); } } else { // We don't have enough space for all rows in out, so use a temp buffer. From 99ab8dfc997b7012b528729cae460bc6af230238 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 00:25:49 +0100 Subject: [PATCH 14/24] Use gameID and emulated timestamp for Avi/Wav dump filenames. --- Core/AVIDump.cpp | 14 ++++++++++++-- Core/HLE/__sceAudio.cpp | 11 +++++++++-- Core/HLE/sceKernelTime.cpp | 4 ++++ Core/HLE/sceKernelTime.h | 1 + 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index e118c390db..5809383135 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -34,6 +34,10 @@ extern "C" { #include "GPU/Common/GPUDebugInterface.h" +#include "Core/ELF/ParamSFO.h" +#include "Core/HLE/sceKernelTime.h" +#include "StringUtils.h" + #ifdef USE_FFMPEG #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1) @@ -86,10 +90,16 @@ bool AVIDump::CreateAVI() { #ifdef USE_FFMPEG AVCodec* codec = nullptr; + // Use gameID_EmulatedTimestamp for filename + std::string discID = g_paramSFO.GetDiscID(); + std::string video_file_name = StringFromFormat("%s%s_%d.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID, returnEmulatedTime()).c_str(); + s_format_context = avformat_alloc_context(); std::stringstream s_file_index_str; - s_file_index_str << s_file_index; - snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", (GetSysDirectory(DIRECTORY_VIDEO) + "framedump" + s_file_index_str.str() + ".avi").c_str()); + s_file_index_str << video_file_name; + + snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", s_file_index_str.str().c_str()); + INFO_LOG(COMMON, "Recording Video to: %s", s_format_context->filename); // Make sure that the path exists if (!File::Exists(GetSysDirectory(DIRECTORY_VIDEO))) File::CreateDir(GetSysDirectory(DIRECTORY_VIDEO)); diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index bf22b2d01b..1b4fc50ef6 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -35,6 +35,9 @@ #include "Core/System.h" #ifndef MOBILE_DEVICE #include "Core/WaveFile.h" +#include "Core/ELF/ParamSFO.h" +#include "Core/HLE/sceKernelTime.h" +#include "StringUtils.h" #endif #include "Core/HLE/__sceAudio.h" #include "Core/HLE/sceAudio.h" @@ -383,9 +386,13 @@ void __AudioUpdate() { #ifndef MOBILE_DEVICE if (!m_logAudio) { if (g_Config.bDumpAudio) { - std::string audio_file_name = GetSysDirectory(DIRECTORY_AUDIO) + "audiodump.wav"; + // Use gameID_EmulatedTimestamp for filename + std::string discID = g_paramSFO.GetDiscID(); + std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID, returnEmulatedTime()).c_str(); + INFO_LOG(COMMON,"Recording audio to: %s", audio_file_name.c_str()); // Create the path just in case it doesn't exist - File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); + if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) + File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); File::CreateEmptyFile(audio_file_name); __StartLogAudio(audio_file_name); } diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 087e8f115b..32265fdf1b 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -171,3 +171,7 @@ u32 sceKernelLibcGettimeofday(u32 timeAddr, u32 tzAddr) hleReSchedule("libc timeofday"); return 0; } + +u32 returnEmulatedTime() { + return (u32)start_time + (u32)(CoreTiming::GetGlobalTimeUs() / 1000000ULL); +} \ No newline at end of file diff --git a/Core/HLE/sceKernelTime.h b/Core/HLE/sceKernelTime.h index 2cbc5ca2fb..df81f20663 100644 --- a/Core/HLE/sceKernelTime.h +++ b/Core/HLE/sceKernelTime.h @@ -27,6 +27,7 @@ int sceKernelSysClock2USec(u32 sysclockPtr, u32 highPtr, u32 lowPtr); int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 highPtr); u64 sceKernelUSec2SysClockWide(u32 usec); u32 sceKernelLibcClock(); +u32 returnEmulatedTime(); void __KernelTimeInit(); void __KernelTimeDoState(PointerWrap &p); From e698414f9bc0c005aeae2bf06911a25cc9603554 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 05:12:27 +0100 Subject: [PATCH 15/24] Add an option to allow resetting video/audio dump on save/load state. --- Core/Config.cpp | 1 + Core/Config.h | 1 + Core/HLE/__sceAudio.cpp | 16 +++++++++++++++- Core/HLE/__sceAudio.h | 8 +++++++- Core/SaveState.cpp | 30 ++++++++++++++++++++++++++++++ UI/GameSettingsScreen.cpp | 1 + 6 files changed, 55 insertions(+), 2 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 9ddda1a9e9..9e0537ed24 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -360,6 +360,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("UseFFV1", &g_Config.bUseFFV1, false), ConfigSetting("DumpFrames", &g_Config.bDumpFrames, false), ConfigSetting("DumpAudio", &g_Config.bDumpAudio, false), + ConfigSetting("SaveLoadResetsAVdumping", &g_Config.bSaveLoadResetsAVdumping, false), ConfigSetting("StateSlot", &g_Config.iCurrentStateSlot, 0, true, true), ConfigSetting("RewindFlipFrequency", &g_Config.iRewindFlipFrequency, 0, true, true), diff --git a/Core/Config.h b/Core/Config.h index 6a1d4c2134..ee63af6f30 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -105,6 +105,7 @@ public: bool bUseFFV1; bool bDumpFrames; bool bDumpAudio; + bool bSaveLoadResetsAVdumping; bool bEnableLogging; bool bDumpDecryptedEboot; bool bFullscreenOnDoubleclick; diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index 1b4fc50ef6..c933b9fa9f 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -331,7 +331,7 @@ void __AudioSetOutputFrequency(int freq) { // Mix samples from the various audio channels into a single sample queue. // This single sample queue is where __AudioMix should read from. If the sample queue is full, we should // just sleep the main emulator thread a little. -void __AudioUpdate() { +void __AudioUpdate(bool resetRecording) { // Audio throttle doesn't really work on the PSP since the mixing intervals are so closely tied // to the CPU. Much better to throttle the frame rate on frame display and just throw away audio // if the buffer somehow gets full. @@ -384,6 +384,16 @@ void __AudioUpdate() { if (g_Config.bEnableSound) { resampler.PushSamples(mixBuffer, hwBlockSize); #ifndef MOBILE_DEVICE + if (g_Config.bSaveLoadResetsAVdumping && resetRecording) { + __StopLogAudio(); + std::string discID = g_paramSFO.GetDiscID(); + std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID, returnEmulatedTime()).c_str(); + INFO_LOG(COMMON, "Restarted audio recording to: %s", audio_file_name.c_str()); + if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) + File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); + File::CreateEmptyFile(audio_file_name); + __StartLogAudio(audio_file_name); + } if (!m_logAudio) { if (g_Config.bDumpAudio) { // Use gameID_EmulatedTimestamp for filename @@ -450,3 +460,7 @@ void __StopLogAudio() { } } #endif + +void WAVDump::Reset() { + __AudioUpdate(true); +} diff --git a/Core/HLE/__sceAudio.h b/Core/HLE/__sceAudio.h index 87365fb361..39f83d8401 100644 --- a/Core/HLE/__sceAudio.h +++ b/Core/HLE/__sceAudio.h @@ -33,7 +33,7 @@ struct AudioDebugStats { void __AudioInit(); void __AudioDoState(PointerWrap &p); -void __AudioUpdate(); +void __AudioUpdate(bool resetRecording = false); void __AudioShutdown(); void __AudioSetOutputFrequency(int freq); @@ -49,3 +49,9 @@ void __PushExternalAudio(const s32 *audio, int numSamples); // Should not be us // Audio Dumping stuff void __StartLogAudio(const std::string& filename); void __StopLogAudio(); + +class WAVDump +{ +public: + static void Reset(); +}; diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 4b5a4a5426..ebed78f879 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -46,6 +46,14 @@ #include "HW/MemoryStick.h" #include "GPU/GPUState.h" +#ifndef MOBILE_DEVICE +#include "Core/AVIDump.h" +#include "Core/HLE/__sceAudio.h" + +AVIDump video; +WAVDump audio; +#endif + namespace SaveState { struct SaveStart @@ -591,6 +599,17 @@ namespace SaveState callbackMessage = sc->T("Loaded State"); callbackResult = true; hasLoadedState = true; +#ifndef MOBILE_DEVICE + if (g_Config.bSaveLoadResetsAVdumping) { + if (g_Config.bDumpFrames) { + video.Stop(); + video.Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); + } + if (g_Config.bDumpAudio) { + audio.Reset(); + } + } +#endif } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { HandleFailure(); callbackMessage = i18nLoadFailure; @@ -615,6 +634,17 @@ namespace SaveState if (result == CChunkFileReader::ERROR_NONE) { callbackMessage = sc->T("Saved State"); callbackResult = true; +#ifndef MOBILE_DEVICE + if (g_Config.bSaveLoadResetsAVdumping) { + if (g_Config.bDumpFrames) { + video.Stop(); + video.Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); + } + if (g_Config.bDumpAudio) { + audio.Reset(); + } + } +#endif } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { HandleFailure(); callbackMessage = i18nSaveFailure; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 68cb2d71bf..5e7d7fa2f7 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -781,6 +781,7 @@ void GameSettingsScreen::CreateViews() { systemSettings->Add(new CheckBox(&g_Config.bDumpFrames, sy->T("Record Display"))); systemSettings->Add(new CheckBox(&g_Config.bUseFFV1, sy->T("Use Lossless Video Codec (FFV1)"))); systemSettings->Add(new CheckBox(&g_Config.bDumpAudio, sy->T("Record Audio"))); + systemSettings->Add(new CheckBox(&g_Config.bSaveLoadResetsAVdumping, sy->T("Reset Recording on Save/Load State"))); #endif systemSettings->Add(new CheckBox(&g_Config.bDayLightSavings, sy->T("Day Light Saving"))); static const char *dateFormat[] = { "YYYYMMDD", "MMDDYYYY", "DDMMYYYY"}; From 992748bcde7eeef25ce53c09ac0c24dec199f0cb Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 05:56:10 +0100 Subject: [PATCH 16/24] Fix linux build. --- Core/AVIDump.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 5809383135..ce02743d02 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -92,7 +92,7 @@ bool AVIDump::CreateAVI() { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - std::string video_file_name = StringFromFormat("%s%s_%d.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID, returnEmulatedTime()).c_str(); + std::string video_file_name = StringFromFormat("%s%s_%d.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), returnEmulatedTime()).c_str(); s_format_context = avformat_alloc_context(); std::stringstream s_file_index_str; From f8f4acc31685327010133b1fd2dda1abd651405a Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 06:03:52 +0100 Subject: [PATCH 17/24] Blah;p. Buildfix. --- Core/HLE/__sceAudio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index c933b9fa9f..a6185256cd 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -387,7 +387,7 @@ void __AudioUpdate(bool resetRecording) { if (g_Config.bSaveLoadResetsAVdumping && resetRecording) { __StopLogAudio(); std::string discID = g_paramSFO.GetDiscID(); - std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID, returnEmulatedTime()).c_str(); + std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), returnEmulatedTime()).c_str(); INFO_LOG(COMMON, "Restarted audio recording to: %s", audio_file_name.c_str()); if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); @@ -398,7 +398,7 @@ void __AudioUpdate(bool resetRecording) { if (g_Config.bDumpAudio) { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID, returnEmulatedTime()).c_str(); + std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), returnEmulatedTime()).c_str(); INFO_LOG(COMMON,"Recording audio to: %s", audio_file_name.c_str()); // Create the path just in case it doesn't exist if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) From 2ff4104ddf2ab185904403b7863fe1fa7f65efda Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 06:33:49 +0100 Subject: [PATCH 18/24] Requested changes. --- Core/AVIDump.cpp | 2 +- Core/HLE/__sceAudio.cpp | 4 ++-- Core/HLE/sceKernelTime.cpp | 2 +- Core/HLE/sceKernelTime.h | 2 +- Core/SaveState.cpp | 15 ++++++--------- UI/EmuScreen.cpp | 2 +- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index ce02743d02..456698936b 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -92,7 +92,7 @@ bool AVIDump::CreateAVI() { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - std::string video_file_name = StringFromFormat("%s%s_%d.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), returnEmulatedTime()).c_str(); + std::string video_file_name = StringFromFormat("%s%s_%d.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), KernelTimeNow()).c_str(); s_format_context = avformat_alloc_context(); std::stringstream s_file_index_str; diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index a6185256cd..ed9c7c1c76 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -387,7 +387,7 @@ void __AudioUpdate(bool resetRecording) { if (g_Config.bSaveLoadResetsAVdumping && resetRecording) { __StopLogAudio(); std::string discID = g_paramSFO.GetDiscID(); - std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), returnEmulatedTime()).c_str(); + std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNow()).c_str(); INFO_LOG(COMMON, "Restarted audio recording to: %s", audio_file_name.c_str()); if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); @@ -398,7 +398,7 @@ void __AudioUpdate(bool resetRecording) { if (g_Config.bDumpAudio) { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), returnEmulatedTime()).c_str(); + std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNow()).c_str(); INFO_LOG(COMMON,"Recording audio to: %s", audio_file_name.c_str()); // Create the path just in case it doesn't exist if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 32265fdf1b..a4f2df2a60 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -172,6 +172,6 @@ u32 sceKernelLibcGettimeofday(u32 timeAddr, u32 tzAddr) return 0; } -u32 returnEmulatedTime() { +u32 KernelTimeNow() { return (u32)start_time + (u32)(CoreTiming::GetGlobalTimeUs() / 1000000ULL); } \ No newline at end of file diff --git a/Core/HLE/sceKernelTime.h b/Core/HLE/sceKernelTime.h index df81f20663..15c064d7ce 100644 --- a/Core/HLE/sceKernelTime.h +++ b/Core/HLE/sceKernelTime.h @@ -27,7 +27,7 @@ int sceKernelSysClock2USec(u32 sysclockPtr, u32 highPtr, u32 lowPtr); int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 highPtr); u64 sceKernelUSec2SysClockWide(u32 usec); u32 sceKernelLibcClock(); -u32 returnEmulatedTime(); +u32 KernelTimeNow(); void __KernelTimeInit(); void __KernelTimeDoState(PointerWrap &p); diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index ebed78f879..7c3719f1a0 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -49,9 +49,6 @@ #ifndef MOBILE_DEVICE #include "Core/AVIDump.h" #include "Core/HLE/__sceAudio.h" - -AVIDump video; -WAVDump audio; #endif namespace SaveState @@ -602,11 +599,11 @@ namespace SaveState #ifndef MOBILE_DEVICE if (g_Config.bSaveLoadResetsAVdumping) { if (g_Config.bDumpFrames) { - video.Stop(); - video.Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); + AVIDump::Stop(); + AVIDump::Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); } if (g_Config.bDumpAudio) { - audio.Reset(); + WAVDump::Reset(); } } #endif @@ -637,11 +634,11 @@ namespace SaveState #ifndef MOBILE_DEVICE if (g_Config.bSaveLoadResetsAVdumping) { if (g_Config.bDumpFrames) { - video.Stop(); - video.Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); + AVIDump::Stop(); + AVIDump::Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight); } if (g_Config.bDumpAudio) { - audio.Reset(); + WAVDump::Reset(); } } #endif diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index fc089d3c3c..f8d8727899 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -79,7 +79,7 @@ #endif #ifndef MOBILE_DEVICE -AVIDump avi; +static AVIDump avi; #endif static bool frameStep_; From aba4a4dfdb21c36b529e39e4f3d0839136bdd092 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 07:16:40 +0100 Subject: [PATCH 19/24] Change KernelTimeNow to KernelTimeNowFormatted and return nice timestamp. --- Core/AVIDump.cpp | 2 +- Core/HLE/__sceAudio.cpp | 4 ++-- Core/HLE/sceKernelTime.cpp | 17 +++++++++++++++-- Core/HLE/sceKernelTime.h | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 456698936b..1255f16089 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -92,7 +92,7 @@ bool AVIDump::CreateAVI() { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - std::string video_file_name = StringFromFormat("%s%s_%d.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), KernelTimeNow()).c_str(); + std::string video_file_name = StringFromFormat("%s%s %s.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); s_format_context = avformat_alloc_context(); std::stringstream s_file_index_str; diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index ed9c7c1c76..c6d1dfefc9 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -387,7 +387,7 @@ void __AudioUpdate(bool resetRecording) { if (g_Config.bSaveLoadResetsAVdumping && resetRecording) { __StopLogAudio(); std::string discID = g_paramSFO.GetDiscID(); - std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNow()).c_str(); + std::string audio_file_name = StringFromFormat("%s%s %s.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); INFO_LOG(COMMON, "Restarted audio recording to: %s", audio_file_name.c_str()); if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); @@ -398,7 +398,7 @@ void __AudioUpdate(bool resetRecording) { if (g_Config.bDumpAudio) { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - std::string audio_file_name = StringFromFormat("%s%s_%d.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNow()).c_str(); + std::string audio_file_name = StringFromFormat("%s%s %s.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); INFO_LOG(COMMON,"Recording audio to: %s", audio_file_name.c_str()); // Create the path just in case it doesn't exist if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index a4f2df2a60..19901cc721 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -31,6 +31,7 @@ #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceRtc.h" #include "Core/MemMap.h" +#include "StringUtils.h" // The time when the game started. static time_t start_time; @@ -172,6 +173,18 @@ u32 sceKernelLibcGettimeofday(u32 timeAddr, u32 tzAddr) return 0; } -u32 KernelTimeNow() { - return (u32)start_time + (u32)(CoreTiming::GetGlobalTimeUs() / 1000000ULL); +std::string KernelTimeNowFormatted() { + time_t emulatedTime = (u32)start_time + (u32)(CoreTiming::GetGlobalTimeUs() / 1000000ULL); + tm* timePtr = localtime(&emulatedTime); + bool DST = timePtr->tm_isdst; + u8 seconds = timePtr->tm_sec; + u8 minutes = timePtr->tm_min; + u8 hours = timePtr->tm_hour; + if (DST) + hours = timePtr->tm_hour + 1; + u8 days = timePtr->tm_mday; + u8 months = timePtr->tm_mon + 1; + u16 years = timePtr->tm_year + 1900; + std::string timestamp = StringFromFormat("%04d-%02d-%02d %02d-%02d-%02d", years, months, days, hours, minutes, seconds).c_str(); + return timestamp; } \ No newline at end of file diff --git a/Core/HLE/sceKernelTime.h b/Core/HLE/sceKernelTime.h index 15c064d7ce..d973c20d40 100644 --- a/Core/HLE/sceKernelTime.h +++ b/Core/HLE/sceKernelTime.h @@ -27,7 +27,7 @@ int sceKernelSysClock2USec(u32 sysclockPtr, u32 highPtr, u32 lowPtr); int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 highPtr); u64 sceKernelUSec2SysClockWide(u32 usec); u32 sceKernelLibcClock(); -u32 KernelTimeNow(); +std::string KernelTimeNowFormatted(); void __KernelTimeInit(); void __KernelTimeDoState(PointerWrap &p); From 825e10061422117e1d2b57ddda3f1fcd25ef90ef Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 07:42:58 +0100 Subject: [PATCH 20/24] Small changes. Thx [Unknown] --- Core/HLE/sceKernelTime.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 19901cc721..ed391be28c 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -174,7 +174,7 @@ u32 sceKernelLibcGettimeofday(u32 timeAddr, u32 tzAddr) } std::string KernelTimeNowFormatted() { - time_t emulatedTime = (u32)start_time + (u32)(CoreTiming::GetGlobalTimeUs() / 1000000ULL); + time_t emulatedTime = (time_t)start_time + (u32)(CoreTiming::GetGlobalTimeUs() / 1000000ULL); tm* timePtr = localtime(&emulatedTime); bool DST = timePtr->tm_isdst; u8 seconds = timePtr->tm_sec; @@ -185,6 +185,6 @@ std::string KernelTimeNowFormatted() { u8 days = timePtr->tm_mday; u8 months = timePtr->tm_mon + 1; u16 years = timePtr->tm_year + 1900; - std::string timestamp = StringFromFormat("%04d-%02d-%02d %02d-%02d-%02d", years, months, days, hours, minutes, seconds).c_str(); + std::string timestamp = StringFromFormat("%04d-%02d-%02d %02d-%02d-%02d", years, months, days, hours, minutes, seconds); return timestamp; } \ No newline at end of file From d4df0181dbfaf93e466d760b2aa9054a050b131e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Nov 2017 18:57:59 +0100 Subject: [PATCH 21/24] More duplicate code removal --- GPU/D3D11/GPU_D3D11.cpp | 51 +++------------------------------------ GPU/D3D11/GPU_D3D11.h | 3 --- GPU/Directx9/GPU_DX9.cpp | 51 +++------------------------------------ GPU/Directx9/GPU_DX9.h | 2 -- GPU/GLES/GPU_GLES.cpp | 49 +++---------------------------------- GPU/GLES/GPU_GLES.h | 5 ---- GPU/GPUCommon.cpp | 43 +++++++++++++++++++++++++++++++++ GPU/GPUCommon.h | 4 +++ GPU/Vulkan/GPU_Vulkan.cpp | 50 +++----------------------------------- GPU/Vulkan/GPU_Vulkan.h | 3 --- 10 files changed, 63 insertions(+), 198 deletions(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 5ca54d603e..760285b5de 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -76,12 +76,12 @@ struct D3D11CommandTableEntry { // 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 }, + { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 }, { GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_FOGCOEF | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE }, // These are combined in D3D11 // Changing the vertex type requires us to flush. - { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_D3D11::Execute_VertexType }, + { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType }, { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Prim }, { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier }, @@ -202,10 +202,10 @@ GPU_D3D11::~GPU_D3D11() { void GPU_D3D11::UpdateCmdInfo() { if (g_Config.bSoftwareSkinning) { cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE; - cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_D3D11::Execute_VertexTypeSkinning; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning; } else { cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE; - cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_D3D11::Execute_VertexType; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType; } CheckGPUFeatures(); @@ -443,37 +443,6 @@ void GPU_D3D11::ExecuteOp(u32 op, u32 diff) { } } -void GPU_D3D11::Execute_VertexType(u32 op, u32 diff) { - if (diff) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) { - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - if (diff & GE_VTYPE_THROUGH_MASK) - gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); - } -} - -void GPU_D3D11::Execute_VertexTypeSkinning(u32 op, u32 diff) { - // Don't flush when weight count changes, unless morph is enabled. - if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { - // Restore and flush - gstate.vertType ^= diff; - Flush(); - gstate.vertType ^= diff; - if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - // In this case, we may be doing weights and morphs. - // Update any bone matrix uniforms so it uses them correctly. - if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { - gstate_c.Dirty(gstate_c.deferredVertTypeDirty); - gstate_c.deferredVertTypeDirty = 0; - } - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - } - if (diff & GE_VTYPE_THROUGH_MASK) - gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); -} - void GPU_D3D11::Execute_Prim(u32 op, u32 diff) { // This drives all drawing. All other state we just buffer up, then we apply it only // when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization. @@ -547,18 +516,6 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) { AdvanceVerts(vertexType, count, bytesRead); } -void GPU_D3D11::Execute_TexSize0(u32 op, u32 diff) { - // Render to texture may have overridden the width/height. - // Don't reset it unless the size is different / the texture has changed. - if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) { - gstate_c.curTextureWidth = gstate.getTextureWidth(0); - gstate_c.curTextureHeight = gstate.getTextureHeight(0); - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - // We will need to reset the texture now. - gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); - } -} - void GPU_D3D11::Execute_LoadClut(u32 op, u32 diff) { gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); textureCacheD3D11_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes()); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index ecf36491ac..9d7ff6bc59 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -68,9 +68,6 @@ public: }; void Execute_Prim(u32 op, u32 diff); - void Execute_VertexType(u32 op, u32 diff); - void Execute_VertexTypeSkinning(u32 op, u32 diff); - void Execute_TexSize0(u32 op, u32 diff); void Execute_LoadClut(u32 op, u32 diff); // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 9d47ba66cc..a9359d46dd 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -60,12 +60,12 @@ struct D3D9CommandTableEntry { // 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 }, + { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 }, { GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE }, // Changing the vertex type requires us to flush. - { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_DX9::Execute_VertexType }, + { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType }, { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_DX9::Execute_Prim }, { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier }, @@ -171,10 +171,10 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) void GPU_DX9::UpdateCmdInfo() { if (g_Config.bSoftwareSkinning) { cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE; - cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_DX9::Execute_VertexTypeSkinning; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning; } else { cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE; - cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_DX9::Execute_VertexType; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType; } CheckGPUFeatures(); @@ -408,37 +408,6 @@ void GPU_DX9::ExecuteOp(u32 op, u32 diff) { } } -void GPU_DX9::Execute_VertexType(u32 op, u32 diff) { - if (diff) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) { - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - if (diff & GE_VTYPE_THROUGH_MASK) - gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE); - } -} - -void GPU_DX9::Execute_VertexTypeSkinning(u32 op, u32 diff) { - // Don't flush when weight count changes, unless morph is enabled. - if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { - // Restore and flush - gstate.vertType ^= diff; - Flush(); - gstate.vertType ^= diff; - if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - // In this case, we may be doing weights and morphs. - // Update any bone matrix uniforms so it uses them correctly. - if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { - gstate_c.Dirty(gstate_c.deferredVertTypeDirty); - gstate_c.deferredVertTypeDirty = 0; - } - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - } - if (diff & GE_VTYPE_THROUGH_MASK) - gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE); -} - void GPU_DX9::Execute_Prim(u32 op, u32 diff) { // This drives all drawing. All other state we just buffer up, then we apply it only // when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization. @@ -511,18 +480,6 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) { AdvanceVerts(vertexType, count, bytesRead); } -void GPU_DX9::Execute_TexSize0(u32 op, u32 diff) { - // Render to texture may have overridden the width/height. - // Don't reset it unless the size is different / the texture has changed. - if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) { - gstate_c.curTextureWidth = gstate.getTextureWidth(0); - gstate_c.curTextureHeight = gstate.getTextureHeight(0); - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - // We will need to reset the texture now. - gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); - } -} - void GPU_DX9::Execute_LoadClut(u32 op, u32 diff) { gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); textureCacheDX9_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes()); diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 33753a59b6..9c0da49c11 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -69,8 +69,6 @@ public: }; void Execute_Prim(u32 op, u32 diff); - void Execute_VertexType(u32 op, u32 diff); - void Execute_VertexTypeSkinning(u32 op, u32 diff); void Execute_TexSize0(u32 op, u32 diff); void Execute_LoadClut(u32 op, u32 diff); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 64ae717b63..eae91ae8d1 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -63,12 +63,12 @@ struct GLESCommandTableEntry { // TODO: Share this table between the backends. Will have to make another indirection for the function pointers though.. static const GLESCommandTableEntry commandTable[] = { // Changes that dirty the current texture. - { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, DIRTY_UVSCALEOFFSET, &GPU_GLES::Execute_TexSize0 }, + { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 }, { GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE }, // Changing the vertex type requires us to flush. - { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_GLES::Execute_VertexType }, + { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType }, { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_GLES::Execute_Prim }, { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier }, @@ -461,10 +461,10 @@ inline void GPU_GLES::UpdateVsyncInterval(bool force) { void GPU_GLES::UpdateCmdInfo() { if (g_Config.bSoftwareSkinning) { cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE; - cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_GLES::Execute_VertexTypeSkinning; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning; } else { cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE; - cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_GLES::Execute_VertexType; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType; } } @@ -688,47 +688,6 @@ void GPU_GLES::Execute_Prim(u32 op, u32 diff) { AdvanceVerts(gstate.vertType, count, bytesRead); } -void GPU_GLES::Execute_VertexType(u32 op, u32 diff) { - if (diff) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) { - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - if (diff & GE_VTYPE_THROUGH_MASK) - gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); - } -} - -void GPU_GLES::Execute_VertexTypeSkinning(u32 op, u32 diff) { - // Don't flush when weight count changes, unless morph is enabled. - if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { - // Restore and flush - gstate.vertType ^= diff; - Flush(); - gstate.vertType ^= diff; - if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - // In this case, we may be doing weights and morphs. - // Update any bone matrix uniforms so it uses them correctly. - if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { - gstate_c.Dirty(gstate_c.deferredVertTypeDirty); - gstate_c.deferredVertTypeDirty = 0; - } - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - } - if (diff & GE_VTYPE_THROUGH_MASK) - gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); -} - -void GPU_GLES::Execute_TexSize0(u32 op, u32 diff) { - // Render to texture may have overridden the width/height. - // Don't reset it unless the size is different / the texture has changed. - if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) { - gstate_c.curTextureWidth = gstate.getTextureWidth(0); - gstate_c.curTextureHeight = gstate.getTextureHeight(0); - gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_TEXTURE_PARAMS); - } -} - void GPU_GLES::Execute_LoadClut(u32 op, u32 diff) { gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); textureCacheGL_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes()); diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index a9662cf271..e3ffb81d4b 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -71,12 +71,7 @@ public: }; void Execute_Prim(u32 op, u32 diff); - void Execute_Bezier(u32 op, u32 diff); - void Execute_Spline(u32 op, u32 diff); void Execute_LoadClut(u32 op, u32 diff); - void Execute_VertexType(u32 op, u32 diff); - void Execute_VertexTypeSkinning(u32 op, u32 diff); - void Execute_TexSize0(u32 op, u32 diff); // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. std::vector DebugGetShaderIDs(DebugShaderType shader) override; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d95a1a6a67..0578ec7bf7 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1323,6 +1323,49 @@ void GPUCommon::Execute_TexLevel(u32 op, u32 diff) { gstate_c.Dirty(DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE); } +void GPUCommon::Execute_TexSize0(u32 op, u32 diff) { + // Render to texture may have overridden the width/height. + // Don't reset it unless the size is different / the texture has changed. + if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) { + gstate_c.curTextureWidth = gstate.getTextureWidth(0); + gstate_c.curTextureHeight = gstate.getTextureHeight(0); + gstate_c.Dirty(DIRTY_UVSCALEOFFSET); + // We will need to reset the texture now. + gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); + } +} + +void GPUCommon::Execute_VertexType(u32 op, u32 diff) { + if (diff) + gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); + if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) { + gstate_c.Dirty(DIRTY_UVSCALEOFFSET); + if (diff & GE_VTYPE_THROUGH_MASK) + gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); + } +} + +void GPUCommon::Execute_VertexTypeSkinning(u32 op, u32 diff) { + // Don't flush when weight count changes, unless morph is enabled. + if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { + // Restore and flush + gstate.vertType ^= diff; + Flush(); + gstate.vertType ^= diff; + if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) + gstate_c.Dirty(DIRTY_UVSCALEOFFSET); + // In this case, we may be doing weights and morphs. + // Update any bone matrix uniforms so it uses them correctly. + if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { + gstate_c.Dirty(gstate_c.deferredVertTypeDirty); + gstate_c.deferredVertTypeDirty = 0; + } + gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); + } + if (diff & GE_VTYPE_THROUGH_MASK) + gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); +} + void GPUCommon::Execute_Bezier(u32 op, u32 diff) { drawEngineCommon_->DispatchFlush(); diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index d3b53ad514..77cf3212f4 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -100,11 +100,15 @@ public: void Execute_Ret(u32 op, u32 diff); void Execute_End(u32 op, u32 diff); + void Execute_VertexType(u32 op, u32 diff); + void Execute_VertexTypeSkinning(u32 op, u32 diff); + void Execute_Bezier(u32 op, u32 diff); void Execute_Spline(u32 op, u32 diff); void Execute_BoundingBox(u32 op, u32 diff); void Execute_BlockTransferStart(u32 op, u32 diff); + void Execute_TexSize0(u32 op, u32 diff); void Execute_TexLevel(u32 op, u32 diff); void Execute_WorldMtxNum(u32 op, u32 diff); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 520f60fca1..bb25eef794 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -58,12 +58,12 @@ GPU_Vulkan::CommandInfo GPU_Vulkan::cmdInfo_[256]; // This table gets crunched into a faster form by init. static const VulkanCommandTableEntry commandTable[] = { // Changes that dirty the current texture. - { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_TexSize0 }, + { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 }, { GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE }, // Changing the vertex type requires us to flush. - { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_Vulkan::Execute_VertexType }, + { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType }, { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_Prim }, { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier }, @@ -372,10 +372,10 @@ void GPU_Vulkan::UpdateVsyncInterval(bool force) { void GPU_Vulkan::UpdateCmdInfo() { if (g_Config.bSoftwareSkinning) { cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE; - cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_Vulkan::Execute_VertexTypeSkinning; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning; } else { cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE; - cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_Vulkan::Execute_VertexType; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType; } } @@ -555,48 +555,6 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) { AdvanceVerts(gstate.vertType, count, bytesRead); } -void GPU_Vulkan::Execute_VertexType(u32 op, u32 diff) { - if (diff) - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) { - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - if (diff & GE_VTYPE_THROUGH_MASK) - gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); - } -} - -void GPU_Vulkan::Execute_VertexTypeSkinning(u32 op, u32 diff) { - // Don't flush when weight count changes, unless morph is enabled. - if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { - // Restore and flush - gstate.vertType ^= diff; - Flush(); - gstate.vertType ^= diff; - if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) - gstate_c.Dirty(DIRTY_UVSCALEOFFSET); - // In this case, we may be doing weights and morphs. - // Update any bone matrix uniforms so it uses them correctly. - if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { - gstate_c.Dirty(gstate_c.deferredVertTypeDirty); - gstate_c.deferredVertTypeDirty = 0; - } - gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE); - } - if (diff & GE_VTYPE_THROUGH_MASK) - gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE); -} - -void GPU_Vulkan::Execute_TexSize0(u32 op, u32 diff) { - // Render to texture may have overridden the width/height. - // Don't reset it unless the size is different / the texture has changed. - if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) { - gstate_c.curTextureWidth = gstate.getTextureWidth(0); - gstate_c.curTextureHeight = gstate.getTextureHeight(0); - // We will need to reset the texture now. - gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_TEXTURE_PARAMS); - } -} - void GPU_Vulkan::Execute_LoadClut(u32 op, u32 diff) { gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); textureCacheVulkan_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes()); diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index f72ab93cc5..caeb71b6e1 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -72,9 +72,6 @@ public: }; void Execute_Prim(u32 op, u32 diff); - void Execute_VertexType(u32 op, u32 diff); - void Execute_VertexTypeSkinning(u32 op, u32 diff); - void Execute_TexSize0(u32 op, u32 diff); void Execute_LoadClut(u32 op, u32 diff); // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. From ce1bc7fc3fa297b21a1dbaa52537e1de3d8b4428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 14 Nov 2017 09:13:13 +0100 Subject: [PATCH 22/24] Fixes problem switching between non-through triangles and rects. Helps a small part of #6554 --- GPU/GPUCommon.h | 4 +++- GPU/Vulkan/DrawEngineVulkan.cpp | 10 +++++++--- GPU/Vulkan/ShaderManagerVulkan.cpp | 5 ++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 77cf3212f4..c4d22dc904 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -129,7 +129,7 @@ public: int EstimatePerVertexCost(); // Note: Not virtual! - inline void Flush(); + void Flush(); #ifdef USE_CRT_DBG #undef new @@ -218,12 +218,14 @@ public: protected: void SetDrawType(DrawType type, GEPrimitiveType prim) { if (type != lastDraw_) { + // We always flush when drawing splines/beziers so no need to do so here gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_VERTEXSHADER_STATE); lastDraw_ = type; } // Prim == RECTANGLES can cause CanUseHardwareTransform to flip, so we need to dirty. // Also, culling may be affected so dirty the raster state. if ((prim == GE_PRIM_RECTANGLES) != (lastPrim_ == GE_PRIM_RECTANGLES)) { + Flush(); gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE); lastPrim_ = prim; } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 180d747d1a..209f5eeaa4 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -362,8 +362,9 @@ void DrawEngineVulkan::EndFrame() { } void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) { - if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX) + if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX) { Flush(); + } // TODO: Is this the right thing to do? if (prim == GE_PRIM_KEEP_PREVIOUS) { @@ -863,7 +864,9 @@ void DrawEngineVulkan::DoFlush() { } if (!lastPipeline_ || !gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) { - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, true); // usehwtransform + _dbg_assert_msg_(G3D, vshader->UseHWTransform(), "Bad vshader"); + if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } @@ -961,7 +964,8 @@ void DrawEngineVulkan::DoFlush() { sampler = nullSampler_; } if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) { - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false); // usehwtransform + _dbg_assert_msg_(G3D, !vshader->UseHWTransform(), "Bad vshader"); if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 9c657d9099..db8b14f990 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -27,6 +27,7 @@ #include "util/text/utf8.h" #include "Common/Vulkan/VulkanContext.h" #include "Common/Vulkan/VulkanMemory.h" +#include "Common/Log.h" #include "Common/Common.h" #include "Core/Config.h" #include "Core/Reporting.h" @@ -201,7 +202,7 @@ void ShaderManagerVulkan::DirtyShader() { DirtyLastShader(); } -void ShaderManagerVulkan::DirtyLastShader() { // disables vertex arrays +void ShaderManagerVulkan::DirtyLastShader() { lastVShader_ = nullptr; lastFShader_ = nullptr; gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); @@ -242,6 +243,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) { *vshader = lastVShader_; *fshader = lastFShader_; + _dbg_assert_msg_(G3D, (*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was cached"); // Already all set, no need to look up in shader maps. return; } @@ -271,6 +273,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader *vshader = vs; *fshader = fs; + _dbg_assert_msg_(G3D, (*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was computed"); } std::vector ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType type) { From e78a644c00cd9684703e15008d6d88b3982fc855 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 09:46:31 +0100 Subject: [PATCH 23/24] spaces->underscores:) --- Core/AVIDump.cpp | 2 +- Core/HLE/__sceAudio.cpp | 4 ++-- Core/HLE/sceKernelTime.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 1255f16089..02c42dd2ee 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -92,7 +92,7 @@ bool AVIDump::CreateAVI() { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - std::string video_file_name = StringFromFormat("%s%s %s.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); + std::string video_file_name = StringFromFormat("%s%s_%s.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); s_format_context = avformat_alloc_context(); std::stringstream s_file_index_str; diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index c6d1dfefc9..09c303fa95 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -387,7 +387,7 @@ void __AudioUpdate(bool resetRecording) { if (g_Config.bSaveLoadResetsAVdumping && resetRecording) { __StopLogAudio(); std::string discID = g_paramSFO.GetDiscID(); - std::string audio_file_name = StringFromFormat("%s%s %s.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); + std::string audio_file_name = StringFromFormat("%s%s_%s.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); INFO_LOG(COMMON, "Restarted audio recording to: %s", audio_file_name.c_str()); if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); @@ -398,7 +398,7 @@ void __AudioUpdate(bool resetRecording) { if (g_Config.bDumpAudio) { // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); - std::string audio_file_name = StringFromFormat("%s%s %s.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); + std::string audio_file_name = StringFromFormat("%s%s_%s.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); INFO_LOG(COMMON,"Recording audio to: %s", audio_file_name.c_str()); // Create the path just in case it doesn't exist if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO))) diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index ed391be28c..b74772df3b 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -185,6 +185,6 @@ std::string KernelTimeNowFormatted() { u8 days = timePtr->tm_mday; u8 months = timePtr->tm_mon + 1; u16 years = timePtr->tm_year + 1900; - std::string timestamp = StringFromFormat("%04d-%02d-%02d %02d-%02d-%02d", years, months, days, hours, minutes, seconds); + std::string timestamp = StringFromFormat("%04d-%02d-%02d_%02d-%02d-%02d", years, months, days, hours, minutes, seconds); return timestamp; } \ No newline at end of file From e5e7ba1b55dee3e5fcfbdb24359a4caa1c488330 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Tue, 14 Nov 2017 10:17:20 +0100 Subject: [PATCH 24/24] Fix Memory Leak :D --- Core/AVIDump.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 02c42dd2ee..6188a2bda8 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -224,6 +224,7 @@ void AVIDump::AddFrame() if (error) ERROR_LOG(G3D, "Error while encoding video: %d", error); #endif + delete[] flipbuffer; } void AVIDump::Stop() {