From a854fbbe76c2994c7aef99ed2ab7ec162785c81e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 10:24:52 +0200 Subject: [PATCH 1/9] fbtex matching: Shrink the matching struct, use TinySet instead of vector to avoid an allocation. --- GPU/Common/FramebufferManagerCommon.cpp | 2 +- GPU/Common/TextureCacheCommon.cpp | 27 +++++++++++++------------ GPU/Common/TextureCacheCommon.h | 13 +++++------- GPU/ge_constants.h | 2 +- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 95535d5317..00f5df9b07 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -905,7 +905,6 @@ void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer } void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb) { - // ugly... if (gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) { gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE); } @@ -922,6 +921,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe } else { DownloadFramebufferOnSwitch(prevVfb); } + textureCache_->ForgetLastTexture(); shaderManager_->DirtyLastShader(); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 98f5d560cf..faa03ad261 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -21,6 +21,7 @@ #include "Common/Common.h" #include "Common/Data/Convert/ColorConv.h" +#include "Common/Data/Collections/TinySet.h" #include "Common/Profiler/Profiler.h" #include "Common/MemoryUtil.h" #include "Common/StringUtils.h" @@ -616,18 +617,18 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &entry, u32 texAddrOffset, AttachCandidate *bestCandidate) const { gpuStats.numFramebufferEvaluations++; - std::vector candidates; + TinySet candidates; const std::vector &framebuffers = framebufferManager_->Framebuffers(); for (VirtualFramebuffer *framebuffer : framebuffers) { FramebufferMatchInfo match{}; if (MatchFramebuffer(entry, framebuffer, texAddrOffset, RASTER_COLOR, &match)) { - candidates.push_back(AttachCandidate{ match, entry, framebuffer, RASTER_COLOR, framebuffer->colorBindSeq }); + candidates.push_back(AttachCandidate{ framebuffer, match, RASTER_COLOR }); } match = {}; if (MatchFramebuffer(entry, framebuffer, texAddrOffset, RASTER_DEPTH, &match)) { - candidates.push_back(AttachCandidate{ match, entry, framebuffer, RASTER_DEPTH, framebuffer->depthBindSeq }); + candidates.push_back(AttachCandidate{ framebuffer, match, RASTER_DEPTH }); } } @@ -640,11 +641,11 @@ bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &en if (Reporting::ShouldLogNTimes("multifbcandidate", 5)) { std::string cands; - for (auto &candidate : candidates) { - cands += candidate.ToString() + "\n"; - } + for (size_t i = 0; i < candidates.size(); i++) { + cands += candidates[i].ToString() + "\n"; + } - WARN_LOG_N_TIMES(multifbcandidate, 5, G3D, "GetFramebufferCandidates: Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s", + WARN_LOG(G3D, "GetFramebufferCandidates: Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s", (int)candidates.size(), entry.addr, texAddrOffset, dimWidth(entry.dim), dimHeight(entry.dim), entry.bufw, GeTextureFormatToString(entry.format), cands.c_str() @@ -653,17 +654,17 @@ bool TextureCacheCommon::GetBestFramebufferCandidate(const TextureDefinition &en // OK, multiple possible candidates. Will need to figure out which one is the most relevant. int bestRelevancy = -1; - int bestIndex = -1; + size_t bestIndex = -1; bool kzCompat = PSP_CoreParameter().compat.flags().SplitFramebufferMargin; // We simply use the sequence counter as relevancy nowadays. - for (int i = 0; i < (int)candidates.size(); i++) { + for (size_t i = 0; i < candidates.size(); i++) { const AttachCandidate &candidate = candidates[i]; - int relevancy = candidate.seqCount; + int relevancy = candidate.channel == RASTER_COLOR ? candidate.fb->colorBindSeq : candidate.fb->depthBindSeq; // Add a small negative penalty if the texture is currently bound as a framebuffer, and offset is not zero. - // Should avoid problems when pingponging two nearby buffers, like in Wipeout Pure in #15927 + // Should avoid problems when pingponging two nearby buffers, like in Wipeout Pure in #15927. if (candidate.channel == RASTER_COLOR && (candidate.match.yOffset != 0 || candidate.match.xOffset != 0) && (candidate.fb->fb_address & 0x1FFFFF) == (gstate.getFrameBufAddress() & 0x1FFFFF)) { @@ -865,7 +866,7 @@ bool TextureCacheCommon::MatchFramebuffer( uint32_t fb_stride = channel == RASTER_DEPTH ? framebuffer->z_stride : framebuffer->fb_stride; GEBufferFormat fb_format = channel == RASTER_DEPTH ? GE_FORMAT_DEPTH16 : framebuffer->fb_format; - if (channel == RASTER_DEPTH && framebuffer->z_address == framebuffer->fb_address) { + if (channel == RASTER_DEPTH && (framebuffer->z_address == framebuffer->fb_address || framebuffer->z_address == 0)) { // Try to avoid silly matches to somewhat malformed buffers. return false; } @@ -2248,7 +2249,7 @@ void TextureCacheCommon::ClearNextFrame() { std::string AttachCandidate::ToString() const { return StringFromFormat("[%s seq:%d C:%08x/%d(%s) Z:%08x/%d X:%d Y:%d reint: %s]", this->channel == RASTER_COLOR ? "COLOR" : "DEPTH", - this->seqCount, + this->channel == RASTER_COLOR ? this->fb->colorBindSeq : this->fb->depthBindSeq, this->fb->fb_address, this->fb->fb_stride, GeBufferFormatToString(this->fb->fb_format), this->fb->z_address, this->fb->z_stride, this->match.xOffset, this->match.yOffset, this->match.reinterpret ? "true" : "false"); diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 547f04bb64..e394923090 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -93,12 +93,11 @@ class VulkanTexture; // Enough information about a texture to match it to framebuffers. struct TextureDefinition { u32 addr; + u16 bufw; + u16 dim; GETextureFormat format; - u32 dim; - u32 bufw; }; - // TODO: Shrink this struct. There is some fluff. // NOTE: These only handle textures loaded directly from PSP memory contents. @@ -209,18 +208,16 @@ typedef std::map> TexCache; #endif struct FramebufferMatchInfo { - int xOffset; - int yOffset; + int16_t xOffset; + int16_t yOffset; bool reinterpret; GEBufferFormat reinterpretTo; }; struct AttachCandidate { - FramebufferMatchInfo match; - TextureDefinition entry; VirtualFramebuffer *fb; + FramebufferMatchInfo match; RasterChannel channel; - int seqCount; std::string ToString() const; }; diff --git a/GPU/ge_constants.h b/GPU/ge_constants.h index 8cd455ba79..3559282c57 100644 --- a/GPU/ge_constants.h +++ b/GPU/ge_constants.h @@ -405,7 +405,7 @@ enum GELightComputation GE_LIGHTCOMP_ONLYPOWDIFFUSE = 2, }; -enum GETextureFormat +enum GETextureFormat : uint8_t { GE_TFMT_5650 = 0, GE_TFMT_5551 = 1, From bd71d8044baa1773eb39e3731a8ffd0a37b90ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 10:46:47 +0200 Subject: [PATCH 2/9] TinySet bugfix, add "append" --- Common/Data/Collections/TinySet.h | 19 ++++++++++++++- unittest/UnitTest.cpp | 40 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/Common/Data/Collections/TinySet.h b/Common/Data/Collections/TinySet.h index 219a26d3cd..5c8c8e78e6 100644 --- a/Common/Data/Collections/TinySet.h +++ b/Common/Data/Collections/TinySet.h @@ -43,6 +43,20 @@ struct TinySet { slowLookup_->push_back(t); return slowLookup_->back(); } + void append(const TinySet &other) { + size_t otherSize = other.size(); + if (size() + otherSize <= MaxFastSize) { + // Fast case + for (int i = 0; i < otherSize; i++) { + fastLookup_[fastCount + i] = other.fastLookup_[i]; + } + fastCount += other.fastCount; + } else { + for (int i = 0; i < otherSize; i++) { + push_back(other[i]); + } + } + } bool contains(T t) const { for (int i = 0; i < fastCount; i++) { if (fastLookup_[i] == t) @@ -79,7 +93,7 @@ struct TinySet { return fastCount == 0; } size_t size() const { - if (fastCount <= MaxFastSize) { + if (!slowLookup_) { return fastCount; } else { return slowLookup_->size() + MaxFastSize; @@ -92,6 +106,9 @@ struct TinySet { return (*slowLookup_)[index - MaxFastSize]; } } + const T &back() const { + return (*this)[size() - 1]; + } private: void insertSlow(T t) { diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index 78a08515d6..4f8239a11b 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -40,6 +40,7 @@ #include #endif +#include "Common/Data/Collections/TinySet.h" #include "Common/Data/Text/Parsers.h" #include "Common/Data/Text/WrapText.h" #include "Common/Data/Encoding/Utf8.h" @@ -308,6 +309,44 @@ bool TestParsers() { return true; } +bool TestTinySet() { + TinySet a; + EXPECT_EQ_INT((int)a.size(), 0); + a.push_back(1); + EXPECT_EQ_INT((int)a.size(), 1); + a.push_back(2); + EXPECT_EQ_INT((int)a.size(), 2); + TinySet b; + b.push_back(8); + b.push_back(9); + b.push_back(10); + EXPECT_EQ_INT((int)b.size(), 3); + + a.append(b); + EXPECT_EQ_INT((int)a.size(), 5); + EXPECT_EQ_INT((int)b.size(), 3); + + b.append(b); + EXPECT_EQ_INT((int)b.size(), 6); + + EXPECT_EQ_INT(a[0], 1); + EXPECT_EQ_INT(a[1], 2); + EXPECT_EQ_INT(a[2], 8); + EXPECT_EQ_INT(a[3], 9); + EXPECT_EQ_INT(a[4], 10); + a.append(a); + EXPECT_EQ_INT(a.size(), 10); + EXPECT_EQ_INT(a[9], 10); + + b.push_back(11); + EXPECT_EQ_INT((int)b.size(), 7); + b.push_back(12); + EXPECT_EQ_INT((int)b.size(), 8); + b.push_back(13); + EXPECT_EQ_INT(b.size(), 9); + return true; +} + bool TestVFPUSinCos() { float sine, cosine; InitVFPUSinCos(); @@ -792,6 +831,7 @@ TestItem availableTests[] = { TEST_ITEM(AndroidContentURI), TEST_ITEM(ThreadManager), TEST_ITEM(WrapText), + TEST_ITEM(TinySet), }; int main(int argc, const char *argv[]) { From 24d674d2bca7836b0bb8055fb04e1aca191758e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 10:52:35 +0200 Subject: [PATCH 3/9] Shrink the TransitionRequest struct, use TinySet --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 5 +++-- Common/GPU/Vulkan/VulkanQueueRunner.h | 4 ++-- Common/GPU/Vulkan/VulkanRenderManager.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 6f84cf4b49..2acf0ff1c0 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -685,7 +685,7 @@ void VulkanQueueRunner::ApplyRenderPassMerge(std::vector &steps) { auto mergeRenderSteps = [](VKRStep *dst, VKRStep *src) { // OK. Now, if it's a render, slurp up all the commands and kill the step. // Also slurp up any pretransitions. - dst->preTransitions.insert(dst->preTransitions.end(), src->preTransitions.begin(), src->preTransitions.end()); + dst->preTransitions.append(src->preTransitions); dst->commands.insert(dst->commands.end(), src->commands.begin(), src->commands.end()); MergeRenderAreaRectInto(&dst->render.renderArea, src->render.renderArea); // So we don't consider it for other things, maybe doesn't matter. @@ -1060,7 +1060,8 @@ void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayou } void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd) { - for (const auto &iter : step.preTransitions) { + for (size_t i = 0; i < step.preTransitions.size(); i++) { + const TransitionRequest &iter = step.preTransitions[i]; if (iter.aspect == VK_IMAGE_ASPECT_COLOR_BIT && iter.fb->color.layout != iter.targetLayout) { recordBarrier_.TransitionImageAuto( iter.fb->color.image, diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index f80a1ba340..ba79634702 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -134,8 +134,8 @@ enum class VKRRenderPassStoreAction : uint8_t { }; struct TransitionRequest { - VkImageAspectFlags aspect; // COLOR or DEPTH VKRFramebuffer *fb; + VkImageAspectFlags aspect; // COLOR or DEPTH VkImageLayout targetLayout; }; @@ -153,7 +153,7 @@ struct VKRStep { VKRStepType stepType; std::vector commands; - std::vector preTransitions; + TinySet preTransitions; TinySet dependencies; const char *tag; union { diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 56bf3ee253..ba2c64f758 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -1189,7 +1189,7 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in // We're done. return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView; } else { - curRenderStep_->preTransitions.push_back({ aspectBit, fb, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }); + curRenderStep_->preTransitions.push_back({ fb, aspectBit, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }); return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView; } } From c9048c3748f8b0c7a3eb158e601a795b8846f863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 11:07:30 +0200 Subject: [PATCH 4/9] Shrink the DeferredDrawcall struct, because why not. Assorted cleanup --- Core/Dialog/PSPDialog.h | 2 +- Core/Dialog/SavedataParam.h | 3 --- GPU/Common/DrawEngineCommon.cpp | 5 ++--- GPU/Common/DrawEngineCommon.h | 2 +- GPU/Common/VertexDecoderCommon.cpp | 3 --- GPU/Common/VertexDecoderCommon.h | 20 ++++++++++---------- 6 files changed, 14 insertions(+), 21 deletions(-) diff --git a/Core/Dialog/PSPDialog.h b/Core/Dialog/PSPDialog.h index 636fc20334..673bd54f9b 100644 --- a/Core/Dialog/PSPDialog.h +++ b/Core/Dialog/PSPDialog.h @@ -129,6 +129,6 @@ protected: private: DialogStatus status = SCE_UTILITY_STATUS_NONE; - UtilityDialogType dialogType_; + UtilityDialogType dialogType_ = UtilityDialogType::NONE; bool volatileLocked_ = false; }; diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index e7bdf9ad46..8599a1428d 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -285,9 +285,6 @@ struct SaveFileInfo PPGeImage *texture = nullptr; - SaveFileInfo() { - } - void DoState(PointerWrap &p); }; diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index cbbf4621be..6bc9d7437f 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -701,12 +701,11 @@ void DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimiti DeferredDrawCall &dc = drawCalls[numDrawCalls]; dc.verts = verts; dc.inds = inds; + dc.vertexCount = vertexCount; dc.indexType = (vertTypeID & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT; dc.prim = prim; - dc.vertexCount = vertexCount; - dc.uvScale = gstate_c.uv; dc.cullMode = cullMode; - + dc.uvScale = gstate_c.uv; if (inds) { GetIndexBounds(inds, vertexCount, vertTypeID, &dc.indexLowerBound, &dc.indexUpperBound); } else { diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index fb1218224b..b55bb85cbd 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -165,10 +165,10 @@ protected: u32 vertexCount; u8 indexType; s8 prim; + u8 cullMode; u16 indexLowerBound; u16 indexUpperBound; UVScale uvScale; - int cullMode; }; enum { MAX_DEFERRED_DRAW_CALLS = 128 }; diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index fd4365d34e..c6a4631636 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -176,9 +176,6 @@ void PrintDecodedVertex(VertexReader &vtx) { printf("P: %f %f %f\n", pos[0], pos[1], pos[2]); } -VertexDecoder::VertexDecoder() : decoded_(nullptr), ptr_(nullptr), jitted_(0), jittedSize_(0) { -} - void VertexDecoder::Step_WeightsU8() const { u8 *wt = (u8 *)(decoded_ + decFmt.w0off); diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 33725facb3..b80c18c2dc 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -125,10 +125,13 @@ public: case DEC_FLOAT_3: { const float *f = (const float *)(data_ + decFmt_.posoff); - memcpy(pos, f, 12); - if (isThrough()) { + pos[0] = f[0]; + pos[1] = f[1]; + if (!isThrough()) { + pos[2] = f[2]; + } else { // Integer value passed in a float. Clamped to 0, 65535. - const float z = (int)pos[2] * (1.0f / 65535.0f); + const float z = (int)f[2] * (1.0f / 65535.0f); pos[2] = z > 1.0f ? 1.0f : (z < 0.0f ? 0.0f : z); } } @@ -443,8 +446,6 @@ struct VertexDecoderOptions { class VertexDecoder { public: - VertexDecoder(); - // A jit cache is not mandatory. void SetVertexType(u32 vtype, const VertexDecoderOptions &options, VertexDecoderJitCache *jitCache = nullptr); @@ -549,11 +550,10 @@ public: int ToString(char *output) const; // Mutable decoder state - mutable u8 *decoded_; - mutable const u8 *ptr_; - - JittedVertexDecoder jitted_; - int32_t jittedSize_; + mutable u8 *decoded_ = nullptr; + mutable const u8 *ptr_ = nullptr; + JittedVertexDecoder jitted_ = 0; + int32_t jittedSize_ = 0; // "Immutable" state, set at startup From 7bced814cec0a3585ef46c6487a2df3c31f17031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 11:54:48 +0200 Subject: [PATCH 5/9] Remove a per-audio-frame allocation in sceAudio --- Core/HLE/__sceAudio.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index 9632d90e0b..3176d26130 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -64,8 +64,8 @@ int srcFrequency = 0; const int hwSampleRate = 44100; -int hwBlockSize = 64; -int hostAttemptBlockSize = 512; +const int hwBlockSize = 64; +const int hostAttemptBlockSize = 512; static int audioIntervalCycles; static int audioHostIntervalCycles; @@ -110,8 +110,6 @@ void __AudioInit() { chanQueueMaxSizeFactor = 2; chanQueueMinSizeFactor = 1; - hwBlockSize = 64; - hostAttemptBlockSize = 512; __AudioCPUMHzChange(); @@ -338,7 +336,8 @@ void __AudioUpdate(bool resetRecording) { // to the CPU. Much better to throttle the frame rate on frame display and just throw away audio // if the buffer somehow gets full. bool firstChannel = true; - std::vector srcBuffer; + const int16_t srcBufferSize = hwBlockSize * 2; + int16_t srcBuffer[srcBufferSize]; for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) { if (!chans[i].reserved) @@ -351,7 +350,7 @@ void __AudioUpdate(bool resetRecording) { } bool needsResample = i == PSP_AUDIO_CHANNEL_SRC && srcFrequency != 0 && srcFrequency != mixFrequency; - size_t sz = needsResample ? (hwBlockSize * 2 * srcFrequency) / mixFrequency : hwBlockSize * 2; + size_t sz = needsResample ? (srcBufferSize * srcFrequency) / mixFrequency : srcBufferSize; if (sz > chanSampleQueues[i].size()) { ERROR_LOG(SCEAUDIO, "Channel %i buffer underrun at %i of %i", i, (int)chanSampleQueues[i].size() / 2, (int)sz / 2); } @@ -372,13 +371,11 @@ void __AudioUpdate(bool resetRecording) { return buf1[sz1 - 1]; }; - srcBuffer.resize(hwBlockSize * 2); - // TODO: This is terrible, since it's doing it by small chunk and discarding frac. const uint32_t ratio = (uint32_t)(65536.0 * srcFrequency / (double)mixFrequency); uint32_t frac = 0; size_t readIndex = 0; - for (size_t outIndex = 0; readIndex < sz && outIndex < srcBuffer.size(); outIndex += 2) { + for (size_t outIndex = 0; readIndex < sz && outIndex < srcBufferSize; outIndex += 2) { size_t readIndex2 = readIndex + 2; int16_t l1 = read(readIndex); int16_t r1 = read(readIndex + 1); @@ -393,8 +390,8 @@ void __AudioUpdate(bool resetRecording) { frac &= 0xffff; } - buf1 = srcBuffer.data(); - sz1 = srcBuffer.size(); + buf1 = srcBuffer; + sz1 = srcBufferSize; buf2 = nullptr; sz2 = 0; } From ecb84987efb49224ac335300652e9511a0be8d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 11:55:14 +0200 Subject: [PATCH 6/9] Remove allocation from the heaviest MemBlockInfo path (BlockTransfer). Required some refactoring. --- Common/StringUtils.cpp | 7 +++-- Common/StringUtils.h | 6 ++-- Core/Debugger/MemBlockInfo.cpp | 54 +++++++++++++++++++++------------ Core/Debugger/MemBlockInfo.h | 4 ++- Core/HLE/ReplaceTables.cpp | 10 +++--- Core/HLE/sceAtrac.cpp | 2 +- Core/HLE/sceDeflt.cpp | 2 +- Core/HLE/sceDmac.cpp | 2 +- Core/HLE/sceKernelInterrupt.cpp | 6 ++-- Core/MemMapHelpers.h | 5 +-- GPU/GPUCommon.cpp | 11 ++++--- GPU/Software/SoftGpu.cpp | 2 +- 12 files changed, 65 insertions(+), 46 deletions(-) diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index c4b88c4c3a..f88f6194ab 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -44,15 +44,16 @@ #include "Common/Buffer.h" #include "Common/StringUtils.h" -void truncate_cpy(char *dest, size_t destSize, const char *src) { +size_t truncate_cpy(char *dest, size_t destSize, const char *src) { size_t len = strlen(src); if (len >= destSize - 1) { memcpy(dest, src, destSize - 1); - dest[destSize - 1] = '\0'; + len = destSize - 1; } else { memcpy(dest, src, len); - dest[len] = '\0'; } + dest[len] = '\0'; + return len; } const char* safe_string(const char* s) { diff --git a/Common/StringUtils.h b/Common/StringUtils.h index 989fe8b9fd..16bfaa18e5 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -78,10 +78,10 @@ std::string ReplaceAll(std::string input, const std::string& src, const std::str void SkipSpace(const char **ptr); -void truncate_cpy(char *dest, size_t destSize, const char *src); +size_t truncate_cpy(char *dest, size_t destSize, const char *src); template -inline void truncate_cpy(char(&out)[Count], const char *src) { - truncate_cpy(out, Count, src); +inline size_t truncate_cpy(char(&out)[Count], const char *src) { + return truncate_cpy(out, Count, src); } const char* safe_string(const char* s); diff --git a/Core/Debugger/MemBlockInfo.cpp b/Core/Debugger/MemBlockInfo.cpp index f0be93ea60..e38b6861b7 100644 --- a/Core/Debugger/MemBlockInfo.cpp +++ b/Core/Debugger/MemBlockInfo.cpp @@ -37,7 +37,8 @@ public: bool Mark(uint32_t addr, uint32_t size, uint64_t ticks, uint32_t pc, bool allocated, const char *tag); bool Find(MemBlockFlags flags, uint32_t addr, uint32_t size, std::vector &results); - bool FastFindWriteTag(MemBlockFlags flags, uint32_t addr, uint32_t size, std::string &result); + // Note that the returned pointer gets invalidated as soon as Mark is called. + const char *FastFindWriteTag(MemBlockFlags flags, uint32_t addr, uint32_t size); void Reset(); void DoState(PointerWrap &p); @@ -151,17 +152,16 @@ bool MemSlabMap::Find(MemBlockFlags flags, uint32_t addr, uint32_t size, std::ve return found; } -bool MemSlabMap::FastFindWriteTag(MemBlockFlags flags, uint32_t addr, uint32_t size, std::string &result) { +const char *MemSlabMap::FastFindWriteTag(MemBlockFlags flags, uint32_t addr, uint32_t size) { uint32_t end = addr + size; Slab *slab = FindSlab(addr); while (slab != nullptr && slab->start < end) { if (slab->pc != 0 || slab->tag[0] != '\0') { - result = slab->tag; - return true; + return slab->tag; } slab = slab->next; } - return false; + return nullptr; } void MemSlabMap::Reset() { @@ -485,7 +485,7 @@ std::vector FindMemInfoByFlag(MemBlockFlags flags, uint32_t start, return results; } -static std::string FindWriteTagByFlag(MemBlockFlags flags, uint32_t start, uint32_t size) { +static const char *FindWriteTagByFlag(MemBlockFlags flags, uint32_t start, uint32_t size) { start &= ~0xC0000000; if (pendingNotifyMinAddr1 < start + size && pendingNotifyMaxAddr1 >= start) @@ -493,37 +493,51 @@ static std::string FindWriteTagByFlag(MemBlockFlags flags, uint32_t start, uint3 if (pendingNotifyMinAddr2 < start + size && pendingNotifyMaxAddr2 >= start) FlushPendingMemInfo(); - std::string tag; if (flags & MemBlockFlags::ALLOC) { - if (allocMap.FastFindWriteTag(MemBlockFlags::ALLOC, start, size, tag)) + const char *tag = allocMap.FastFindWriteTag(MemBlockFlags::ALLOC, start, size); + if (tag) return tag; } if (flags & MemBlockFlags::SUB_ALLOC) { - if (suballocMap.FastFindWriteTag(MemBlockFlags::SUB_ALLOC, start, size, tag)) + const char *tag = suballocMap.FastFindWriteTag(MemBlockFlags::SUB_ALLOC, start, size); + if (tag) return tag; } if (flags & MemBlockFlags::WRITE) { - if (writeMap.FastFindWriteTag(MemBlockFlags::WRITE, start, size, tag)) + const char *tag = writeMap.FastFindWriteTag(MemBlockFlags::WRITE, start, size); + if (tag) return tag; } if (flags & MemBlockFlags::TEXTURE) { - if (textureMap.FastFindWriteTag(MemBlockFlags::TEXTURE, start, size, tag)) + const char *tag = textureMap.FastFindWriteTag(MemBlockFlags::TEXTURE, start, size); + if (tag) return tag; } - return ""; + return nullptr; } -std::string GetMemWriteTagAt(uint32_t start, uint32_t size) { - std::string tag = FindWriteTagByFlag(MemBlockFlags::WRITE, start, size); - if (!tag.empty() && tag != "MemInit") - return tag; - +std::string GetMemWriteTagAt(const char *prefix, uint32_t start, uint32_t size) { + const char *tag = FindWriteTagByFlag(MemBlockFlags::WRITE, start, size); + if (tag && strcmp(tag, "MemInit") != 0) + return std::string(prefix) + tag; // Fall back to alloc and texture, especially for VRAM. We prefer write above. tag = FindWriteTagByFlag(MemBlockFlags::ALLOC | MemBlockFlags::TEXTURE, start, size); - if (!tag.empty()) - return tag; + if (tag) + return std::string(prefix) + tag; + return StringFromFormat("%s%08x_size_%08x", prefix, start, size); +} - return StringFromFormat("%08x_size_%08x", start, size); +size_t FormatMemWriteTagAt(char *buf, size_t sz, const char *prefix, uint32_t start, uint32_t size) { + const char *tag = FindWriteTagByFlag(MemBlockFlags::WRITE, start, size); + if (tag && strcmp(tag, "MemInit") != 0) { + return snprintf(buf, sz, "%s%s", prefix, tag); + } + // Fall back to alloc and texture, especially for VRAM. We prefer write above. + tag = FindWriteTagByFlag(MemBlockFlags::ALLOC | MemBlockFlags::TEXTURE, start, size); + if (tag) { + return snprintf(buf, sz, "%s%s", prefix, tag); + } + return snprintf(buf, sz, "%s%08x_size_%08x", prefix, start, size); } void MemBlockInfoInit() { diff --git a/Core/Debugger/MemBlockInfo.h b/Core/Debugger/MemBlockInfo.h index 50e3bfae53..839249f3a2 100644 --- a/Core/Debugger/MemBlockInfo.h +++ b/Core/Debugger/MemBlockInfo.h @@ -68,7 +68,9 @@ inline void NotifyMemInfo(MemBlockFlags flags, uint32_t start, uint32_t size, co std::vector FindMemInfo(uint32_t start, uint32_t size); std::vector FindMemInfoByFlag(MemBlockFlags flags, uint32_t start, uint32_t size); -std::string GetMemWriteTagAt(uint32_t start, uint32_t size); +std::string GetMemWriteTagAt(const char *prefix, uint32_t start, uint32_t size); +// Same as above but allocation-free. +size_t FormatMemWriteTagAt(char *buf, size_t sz, const char *prefix, uint32_t start, uint32_t size); void MemBlockInfoInit(); void MemBlockInfoShutdown(); diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 57603ccf2c..462bad0a7e 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -159,7 +159,7 @@ static int Replace_memcpy() { RETURN(destPtr); if (MemBlockInfoDetailed(bytes)) { - const std::string tag = "ReplaceMemcpy/" + GetMemWriteTagAt(srcPtr, bytes); + const std::string tag = GetMemWriteTagAt("ReplaceMemcpy/", srcPtr, bytes); NotifyMemInfo(MemBlockFlags::READ, srcPtr, bytes, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, destPtr, bytes, tag.c_str(), tag.size()); @@ -211,7 +211,7 @@ static int Replace_memcpy_jak() { RETURN(destPtr); if (MemBlockInfoDetailed(bytes)) { - const std::string tag = "ReplaceMemcpy/" + GetMemWriteTagAt(srcPtr, bytes); + const std::string tag = GetMemWriteTagAt("ReplaceMemcpy/", srcPtr, bytes); NotifyMemInfo(MemBlockFlags::READ, srcPtr, bytes, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, destPtr, bytes, tag.c_str(), tag.size()); @@ -249,7 +249,7 @@ static int Replace_memcpy16() { RETURN(destPtr); if (MemBlockInfoDetailed(bytes)) { - const std::string tag = "ReplaceMemcpy16/" + GetMemWriteTagAt(srcPtr, bytes); + const std::string tag = GetMemWriteTagAt("ReplaceMemcpy16/", srcPtr, bytes); NotifyMemInfo(MemBlockFlags::READ, srcPtr, bytes, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, destPtr, bytes, tag.c_str(), tag.size()); } @@ -290,7 +290,7 @@ static int Replace_memcpy_swizzled() { RETURN(0); if (MemBlockInfoDetailed(pitch * h)) { - const std::string tag = "ReplaceMemcpySwizzle/" + GetMemWriteTagAt(srcPtr, pitch * h); + const std::string tag = GetMemWriteTagAt("ReplaceMemcpySwizzle/", srcPtr, pitch * h); NotifyMemInfo(MemBlockFlags::READ, srcPtr, pitch * h, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, destPtr, pitch * h, tag.c_str(), tag.size()); } @@ -321,7 +321,7 @@ static int Replace_memmove() { RETURN(destPtr); if (MemBlockInfoDetailed(bytes)) { - const std::string tag = "ReplaceMemmove/" + GetMemWriteTagAt(srcPtr, bytes); + const std::string tag = GetMemWriteTagAt("ReplaceMemmove/", srcPtr, bytes); NotifyMemInfo(MemBlockFlags::READ, srcPtr, bytes, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, destPtr, bytes, tag.c_str(), tag.size()); } diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 6ee643fe5a..b22c439bc1 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1268,7 +1268,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 if (outbufPtr != 0) { u32 outBytes = numSamples * atrac->outputChannels_ * sizeof(s16); if (packetAddr != 0 && MemBlockInfoDetailed()) { - const std::string tag = "AtracDecode/" + GetMemWriteTagAt(packetAddr, packetSize); + const std::string tag = GetMemWriteTagAt("AtracDecode/", packetAddr, packetSize); NotifyMemInfo(MemBlockFlags::READ, packetAddr, packetSize, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, tag.c_str(), tag.size()); } else { diff --git a/Core/HLE/sceDeflt.cpp b/Core/HLE/sceDeflt.cpp index d5580dcc40..985b89d543 100644 --- a/Core/HLE/sceDeflt.cpp +++ b/Core/HLE/sceDeflt.cpp @@ -59,7 +59,7 @@ static int CommonDecompress(int windowBits, u32 OutBuffer, int OutBufferLength, } if (MemBlockInfoDetailed(stream.total_in, stream.total_out)) { - const std::string tag = "sceDeflt/" + GetMemWriteTagAt(InBuffer, stream.total_in); + const std::string tag = GetMemWriteTagAt("sceDeflt/", InBuffer, stream.total_in); NotifyMemInfo(MemBlockFlags::READ, InBuffer, stream.total_in, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, OutBuffer, stream.total_out, tag.c_str(), tag.size()); } diff --git a/Core/HLE/sceDmac.cpp b/Core/HLE/sceDmac.cpp index 86c8e60a1e..5fba8f9b94 100644 --- a/Core/HLE/sceDmac.cpp +++ b/Core/HLE/sceDmac.cpp @@ -52,7 +52,7 @@ static int __DmacMemcpy(u32 dst, u32 src, u32 size) { if (!skip) { currentMIPS->InvalidateICache(src, size); if (MemBlockInfoDetailed(size)) { - const std::string tag = "DmacMemcpy/" + GetMemWriteTagAt(src, size); + const std::string tag = GetMemWriteTagAt("DmacMemcpy/", src, size); Memory::Memcpy(dst, src, size, tag.c_str(), tag.size()); } else { Memory::Memcpy(dst, src, size, "DmacMemcpy"); diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index a86deee9fe..cffedaeb46 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -656,7 +656,7 @@ static u32 sceKernelMemcpy(u32 dst, u32 src, u32 size) } if (MemBlockInfoDetailed(size)) { - const std::string tag = "KernelMemcpy/" + GetMemWriteTagAt(src, size); + const std::string tag = GetMemWriteTagAt("KernelMemcpy/", src, size); NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, dst, size, tag.c_str(), tag.size()); } @@ -691,7 +691,7 @@ static u32 sysclib_memcpy(u32 dst, u32 src, u32 size) { memcpy(Memory::GetPointerWriteUnchecked(dst), Memory::GetPointerUnchecked(src), size); } if (MemBlockInfoDetailed(size)) { - const std::string tag = "KernelMemcpy/" + GetMemWriteTagAt(src, size); + const std::string tag = GetMemWriteTagAt("KernelMemcpy/", src, size); NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, dst, size, tag.c_str(), tag.size()); } @@ -794,7 +794,7 @@ static u32 sysclib_memmove(u32 dst, u32 src, u32 size) { memmove(Memory::GetPointerWriteUnchecked(dst), Memory::GetPointerUnchecked(src), size); } if (MemBlockInfoDetailed(size)) { - const std::string tag = "KernelMemmove/" + GetMemWriteTagAt(src, size); + const std::string tag = GetMemWriteTagAt("KernelMemmove/", src, size); NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, dst, size, tag.c_str(), tag.size()); } diff --git a/Core/MemMapHelpers.h b/Core/MemMapHelpers.h index 848bfa73b6..e623d9e768 100644 --- a/Core/MemMapHelpers.h +++ b/Core/MemMapHelpers.h @@ -20,6 +20,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/StringUtils.h" #include "Core/Debugger/MemBlockInfo.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" @@ -70,9 +71,9 @@ inline void Memcpy(const u32 to_address, const u32 from_address, const u32 len, if (MemBlockInfoDetailed(len)) { char tagData[128]; if (!tag) { - const std::string srcTag = GetMemWriteTagAt(from_address, len); + const std::string srcTag = GetMemWriteTagAt("Memcpy/", from_address, len); tag = tagData; - tagLen = snprintf(tagData, sizeof(tagData), "Memcpy/%s", srcTag.c_str()); + tagLen = truncate_cpy(tagData, srcTag.c_str()); } NotifyMemInfo(MemBlockFlags::READ, from_address, len, tag, tagLen); NotifyMemInfo(MemBlockFlags::WRITE, to_address, len, tag, tagLen); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 22b323c713..60383b6c86 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2864,9 +2864,10 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) { if (MemBlockInfoDetailed(numBytes, numBytes)) { const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp; const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp; - const std::string tag = "GPUBlockTransfer/" + GetMemWriteTagAt(src, srcSize); - NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); - NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); + char tag[128]; + size_t tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, srcSize); + NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag, tagSize); + NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag, tagSize); } // TODO: Correct timing appears to be 1.9, but erring a bit low since some of our other timing is inaccurate. @@ -2881,7 +2882,7 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size) { // Since they're identical we don't need to copy. if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) { if (MemBlockInfoDetailed(size)) { - const std::string tag = "GPUMemcpy/" + GetMemWriteTagAt(src, size); + const std::string tag = GetMemWriteTagAt("GPUMemcpy/", src, size); Memory::Memcpy(dest, src, size, tag.c_str(), tag.size()); } else { Memory::Memcpy(dest, src, size, "GPUMemcpy"); @@ -2893,7 +2894,7 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size) { } if (MemBlockInfoDetailed(size)) { - const std::string tag = "GPUMemcpy/" + GetMemWriteTagAt(src, size); + const std::string tag = GetMemWriteTagAt("GPUMemcpy/", src, size); NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, dest, size, tag.c_str(), tag.size()); } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index dd4b71b166..8c26eac9b1 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -813,7 +813,7 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { } if (MemBlockInfoDetailed(srcSize, dstSize)) { - const std::string tag = "GPUBlockTransfer/" + GetMemWriteTagAt(src, srcSize); + const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize); NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size()); NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size()); } From 7c5d36eca76c905a122c191858938191724edab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 13:33:46 +0200 Subject: [PATCH 7/9] libretro buildfix --- libretro/libretro.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 636da101d9..a2adf4c4fa 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -379,7 +379,7 @@ class LibretroHost : public Host void InitSound() override {} void UpdateSound() override { - extern int hostAttemptBlockSize; + extern const int hostAttemptBlockSize; const int blockSizeMax = 512; static int16_t audio[blockSizeMax * 2]; assert(hostAttemptBlockSize <= blockSizeMax); From 1cd34f9d2bef6c92ed457c6aa85bf4d9b5111e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 14:07:14 +0200 Subject: [PATCH 8/9] Another buildfix attempt --- Core/HLE/__sceAudio.cpp | 5 +++++ Core/HLE/__sceAudio.h | 2 ++ libretro/libretro.cpp | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index 3176d26130..f05ad9dfca 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -82,6 +82,11 @@ static bool m_logAudio; static int chanQueueMaxSizeFactor; static int chanQueueMinSizeFactor; +// Accessor for libretro +int __AudioGetHostAttemptBlockSize() { + return hostAttemptBlockSize; +} + static void hleAudioUpdate(u64 userdata, int cyclesLate) { // Schedule the next cycle first. __AudioUpdate() may consume cycles. CoreTiming::ScheduleEvent(audioIntervalCycles - cyclesLate, eventAudioUpdate, 0); diff --git a/Core/HLE/__sceAudio.h b/Core/HLE/__sceAudio.h index ae9ca35126..f26ae0dc77 100644 --- a/Core/HLE/__sceAudio.h +++ b/Core/HLE/__sceAudio.h @@ -50,6 +50,8 @@ int __AudioMix(short *outstereo, int numSamples, int sampleRate); void __AudioGetDebugStats(char *buf, size_t bufSize); void __PushExternalAudio(const s32 *audio, int numSamples); // Should not be used in-game, only at the menu! +int __AudioGetHostAttemptBlockSize(); + // Audio Dumping stuff void __StartLogAudio(const Path &filename); void __StopLogAudio(); diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index a2adf4c4fa..a5a720b7a7 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -379,7 +379,7 @@ class LibretroHost : public Host void InitSound() override {} void UpdateSound() override { - extern const int hostAttemptBlockSize; + int hostAttemptBlockSize = __AudioGetHostAttemptBlockSize(); const int blockSizeMax = 512; static int16_t audio[blockSizeMax * 2]; assert(hostAttemptBlockSize <= blockSizeMax); From 9097fdaae61f9d39cc06758643c9de3a2f0a1852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Sep 2022 14:21:34 +0200 Subject: [PATCH 9/9] Shrink VkRenderData from 88 to 64 bytes. --- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 19 ++++++++++++++----- Common/GPU/Vulkan/VulkanQueueRunner.h | 12 ++++++------ Common/GPU/Vulkan/VulkanRenderManager.h | 16 ++++++++-------- Common/GPU/Vulkan/thin3d_vulkan.cpp | 10 +++++----- GPU/Vulkan/DrawEngineVulkan.cpp | 12 ++++++------ 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 2acf0ff1c0..b00ec67a01 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -347,6 +347,7 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &st profile->cpuStartTime = time_now_d(); bool emitLabels = vulkan_->Extensions().EXT_debug_utils; + for (size_t i = 0; i < steps.size(); i++) { const VKRStep &step = *steps[i]; @@ -1152,6 +1153,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c // The stencil ones are very commonly mostly redundant so let's eliminate them where possible. // Might also want to consider scissor and viewport. VkPipeline lastPipeline = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + int lastStencilWriteMask = -1; int lastStencilCompareMask = -1; int lastStencilReference = -1; @@ -1167,6 +1170,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkPipeline pipeline = c.pipeline.pipeline; if (pipeline != lastGraphicsPipeline) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + pipelineLayout = c.pipeline.pipelineLayout; lastGraphicsPipeline = pipeline; // Reset dynamic state so it gets refreshed with the new pipeline. lastStencilWriteMask = -1; @@ -1188,6 +1192,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } if (pipeline->pipeline != lastGraphicsPipeline && pipeline->pipeline != VK_NULL_HANDLE) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); + pipelineLayout = c.pipeline.pipelineLayout; lastGraphicsPipeline = pipeline->pipeline; // Reset dynamic state so it gets refreshed with the new pipeline. lastStencilWriteMask = -1; @@ -1209,6 +1214,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } if (pipeline->pipeline != lastComputePipeline && pipeline->pipeline != VK_NULL_HANDLE) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline); + pipelineLayout = c.pipeline.pipelineLayout; lastComputePipeline = pipeline->pipeline; } break; @@ -1258,7 +1264,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } case VKRRenderCommand::PUSH_CONSTANTS: - vkCmdPushConstants(cmd, c.push.pipelineLayout, c.push.stages, c.push.offset, c.push.size, c.push.data); + vkCmdPushConstants(cmd, pipelineLayout, c.push.stages, c.push.offset, c.push.size, c.push.data); break; case VKRRenderCommand::STENCIL: @@ -1277,14 +1283,17 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c break; case VKRRenderCommand::DRAW_INDEXED: - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.drawIndexed.pipelineLayout, 0, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); - vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, c.drawIndexed.indexType); - vkCmdBindVertexBuffers(cmd, 0, 1, &c.drawIndexed.vbuffer, &c.drawIndexed.voffset); + { + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); + vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, (VkIndexType)c.drawIndexed.indexType); + VkDeviceSize voffset = c.drawIndexed.voffset; + vkCmdBindVertexBuffers(cmd, 0, 1, &c.drawIndexed.vbuffer, &voffset); vkCmdDrawIndexed(cmd, c.drawIndexed.count, c.drawIndexed.instances, 0, 0, 0); break; + } case VKRRenderCommand::DRAW: - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.draw.pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); if (c.draw.vbuffer) { vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset); } diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index ba79634702..401a125d6b 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -52,15 +52,17 @@ struct VkRenderData { union { struct { VkPipeline pipeline; + VkPipelineLayout pipelineLayout; } pipeline; struct { VKRGraphicsPipeline *pipeline; + VkPipelineLayout pipelineLayout; } graphics_pipeline; struct { VKRComputePipeline *pipeline; + VkPipelineLayout pipelineLayout; } compute_pipeline; struct { - VkPipelineLayout pipelineLayout; VkDescriptorSet ds; int numUboOffsets; uint32_t uboOffsets[3]; @@ -70,17 +72,16 @@ struct VkRenderData { uint32_t offset; } draw; struct { - VkPipelineLayout pipelineLayout; VkDescriptorSet ds; int numUboOffsets; uint32_t uboOffsets[3]; VkBuffer vbuffer; // might need to increase at some point - VkDeviceSize voffset; VkBuffer ibuffer; - VkDeviceSize ioffset; + uint32_t voffset; + uint32_t ioffset; uint32_t count; int16_t instances; - VkIndexType indexType; + int16_t indexType; } drawIndexed; struct { uint32_t clearColor; @@ -103,7 +104,6 @@ struct VkRenderData { uint32_t color; } blendColor; struct { - VkPipelineLayout pipelineLayout; VkShaderStageFlags stages; uint8_t offset; uint8_t size; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 1df2fc2361..a541bea57e 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -242,29 +242,32 @@ public: return pipeline; } - void BindPipeline(VkPipeline pipeline, PipelineFlags flags) { + void BindPipeline(VkPipeline pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != VK_NULL_HANDLE); VkRenderData data{ VKRRenderCommand::BIND_PIPELINE }; data.pipeline.pipeline = pipeline; + data.pipeline.pipelineLayout = pipelineLayout; curPipelineFlags_ |= flags; curRenderStep_->commands.push_back(data); } - void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags) { + void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != nullptr); VkRenderData data{ VKRRenderCommand::BIND_GRAPHICS_PIPELINE }; data.graphics_pipeline.pipeline = pipeline; + data.graphics_pipeline.pipelineLayout = pipelineLayout; curPipelineFlags_ |= flags; curRenderStep_->commands.push_back(data); } - void BindPipeline(VKRComputePipeline *pipeline, PipelineFlags flags) { + void BindPipeline(VKRComputePipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != nullptr); VkRenderData data{ VKRRenderCommand::BIND_COMPUTE_PIPELINE }; data.compute_pipeline.pipeline = pipeline; + data.compute_pipeline.pipelineLayout = pipelineLayout; curPipelineFlags_ |= flags; curRenderStep_->commands.push_back(data); } @@ -351,7 +354,6 @@ public: _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(size + offset < 40); VkRenderData data{ VKRRenderCommand::PUSH_CONSTANTS }; - data.push.pipelineLayout = pipelineLayout; data.push.stages = stages; data.push.offset = offset; data.push.size = size; @@ -386,12 +388,11 @@ public: curRenderStep_->render.stencilStore = VKRRenderPassStoreAction::DONT_CARE; } - void Draw(VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count, int offset = 0) { + void Draw(VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count, int offset = 0) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER && curStepHasViewport_ && curStepHasScissor_); VkRenderData data{ VKRRenderCommand::DRAW }; data.draw.count = count; data.draw.offset = offset; - data.draw.pipelineLayout = layout; data.draw.ds = descSet; data.draw.vbuffer = vbuffer; data.draw.voffset = voffset; @@ -403,12 +404,11 @@ public: curRenderStep_->render.numDraws++; } - void DrawIndexed(VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, int numInstances, VkIndexType indexType) { + void DrawIndexed(VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, int numInstances, VkIndexType indexType) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER && curStepHasViewport_ && curStepHasScissor_); VkRenderData data{ VKRRenderCommand::DRAW_INDEXED }; data.drawIndexed.count = count; data.drawIndexed.instances = numInstances; - data.drawIndexed.pipelineLayout = layout; data.drawIndexed.ds = descSet; data.drawIndexed.vbuffer = vbuffer; data.drawIndexed.voffset = voffset; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 171decd3eb..d6cc587944 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1339,7 +1339,7 @@ void VKContext::Draw(int vertexCount, int offset) { BindCompatiblePipeline(); ApplyDynamicState(); - renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount, offset); + renderManager_.Draw(descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount, offset); } void VKContext::DrawIndexed(int vertexCount, int offset) { @@ -1359,7 +1359,7 @@ void VKContext::DrawIndexed(int vertexCount, int offset) { BindCompatiblePipeline(); ApplyDynamicState(); - renderManager_.DrawIndexed(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vulkanIbuf, (int)ibBindOffset + offset * sizeof(uint32_t), vertexCount, 1, VK_INDEX_TYPE_UINT16); + renderManager_.DrawIndexed(descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vulkanIbuf, (int)ibBindOffset + offset * sizeof(uint32_t), vertexCount, 1, VK_INDEX_TYPE_UINT16); } void VKContext::DrawUP(const void *vdata, int vertexCount) { @@ -1375,15 +1375,15 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) { BindCompatiblePipeline(); ApplyDynamicState(); - renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount); + renderManager_.Draw(descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount); } void VKContext::BindCompatiblePipeline() { VkRenderPass renderPass = renderManager_.GetCompatibleRenderPass(); if (renderPass == renderManager_.GetBackbufferRenderPass()) { - renderManager_.BindPipeline(curPipeline_->backbufferPipeline, curPipeline_->flags); + renderManager_.BindPipeline(curPipeline_->backbufferPipeline, curPipeline_->flags, pipelineLayout_); } else { - renderManager_.BindPipeline(curPipeline_->framebufferPipeline, curPipeline_->flags); + renderManager_.BindPipeline(curPipeline_->framebufferPipeline, curPipeline_->flags, pipelineLayout_); } } diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 37243cac85..60997e582a 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -787,7 +787,7 @@ void DrawEngineVulkan::DoFlush() { lastRenderStepId_ = curRenderStepId; } - renderManager->BindPipeline(pipeline->pipeline, (PipelineFlags)pipeline->flags); + renderManager->BindPipeline(pipeline->pipeline, (PipelineFlags)pipeline->flags, pipelineLayout_); if (pipeline != lastPipeline_) { if (lastPipeline_ && !(lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant())) { gstate_c.Dirty(DIRTY_BLEND_STATE); @@ -814,9 +814,9 @@ void DrawEngineVulkan::DoFlush() { if (!ibuf) { ibOffset = (uint32_t)frameData.pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf); } - renderManager->DrawIndexed(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, 1, VK_INDEX_TYPE_UINT16); + renderManager->DrawIndexed(ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, 1, VK_INDEX_TYPE_UINT16); } else { - renderManager->Draw(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, vertexCount); + renderManager->Draw(ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, vertexCount); } } else { PROFILE_THIS_SCOPE("soft"); @@ -917,7 +917,7 @@ void DrawEngineVulkan::DoFlush() { lastRenderStepId_ = curRenderStepId; } - renderManager->BindPipeline(pipeline->pipeline, (PipelineFlags)pipeline->flags); + renderManager->BindPipeline(pipeline->pipeline, (PipelineFlags)pipeline->flags, pipelineLayout_); if (pipeline != lastPipeline_) { if (lastPipeline_ && !lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant()) { gstate_c.Dirty(DIRTY_BLEND_STATE); @@ -949,11 +949,11 @@ void DrawEngineVulkan::DoFlush() { VkBuffer vbuf, ibuf; vbOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, maxIndex * sizeof(TransformedVertex), &vbuf); ibOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(short) * result.drawNumTrans, &ibuf); - renderManager->DrawIndexed(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, result.drawNumTrans, 1, VK_INDEX_TYPE_UINT16); + renderManager->DrawIndexed(ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, result.drawNumTrans, 1, VK_INDEX_TYPE_UINT16); } else { VkBuffer vbuf; vbOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, result.drawNumTrans * sizeof(TransformedVertex), &vbuf); - renderManager->Draw(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, result.drawNumTrans); + renderManager->Draw(ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, result.drawNumTrans); } } else if (result.action == SW_CLEAR) { // Note: we won't get here if the clear is alpha but not color, or color but not alpha.