From 19931c003f94da327b068f5b298134a1dca16eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 Aug 2022 23:21:14 +0200 Subject: [PATCH 01/35] Clean up blit/copy feature detection. Don't need fast GPU flags for these. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 1 + Common/GPU/D3D9/thin3d_d3d9.cpp | 23 ++++++++++++++++++----- Common/GPU/OpenGL/thin3d_gl.cpp | 4 +++- Common/GPU/Vulkan/thin3d_vulkan.cpp | 21 +++++++++++++++------ Common/GPU/thin3d.h | 3 +++ GPU/Common/FramebufferManagerCommon.cpp | 17 +++++++++-------- GPU/D3D11/GPU_D3D11.cpp | 1 - GPU/GLES/GPU_GLES.cpp | 7 ------- GPU/GLES/StencilBufferGLES.cpp | 2 +- GPU/GPUState.h | 6 ++---- GPU/Vulkan/GPU_Vulkan.cpp | 6 ------ 11 files changed, 52 insertions(+), 39 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 9d13d0789d..a9a922cf24 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -283,6 +283,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.framebufferCopySupported = true; caps_.framebufferDepthBlitSupported = false; caps_.framebufferDepthCopySupported = true; + caps_.framebufferSeparateDepthCopySupported = false; caps_.texture3DSupported = true; D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 9afba75110..684b727cc5 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -667,6 +667,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.framebufferCopySupported = false; caps_.framebufferDepthBlitSupported = true; caps_.framebufferDepthCopySupported = false; + caps_.framebufferSeparateDepthCopySupported = false; caps_.texture3DSupported = true; if (d3d) { @@ -1241,14 +1242,26 @@ void D3D9Context::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) { D3D9Framebuffer *src = (D3D9Framebuffer *)srcfb; D3D9Framebuffer *dst = (D3D9Framebuffer *)dstfb; - if (channelBits != FB_COLOR_BIT) - return false; + + LPDIRECT3DSURFACE9 srcSurf; + LPDIRECT3DSURFACE9 dstSurf; RECT srcRect{ (LONG)srcX1, (LONG)srcY1, (LONG)srcX2, (LONG)srcY2 }; RECT dstRect{ (LONG)dstX1, (LONG)dstY1, (LONG)dstX2, (LONG)dstY2 }; - LPDIRECT3DSURFACE9 srcSurf = src ? src->surf : deviceRTsurf; - LPDIRECT3DSURFACE9 dstSurf = dst ? dst->surf : deviceRTsurf; + if (channelBits == FB_COLOR_BIT) { + srcSurf = src ? src->surf : deviceRTsurf; + dstSurf = dst ? dst->surf : deviceRTsurf; + } else if (channelBits & FB_DEPTH_BIT) { + if (!src || !dst) { + // Might have implications for non-buffered rendering. + return false; + } + srcSurf = src->depthstencil; + dstSurf = dst->depthstencil; + } else { + return false; + } stepId_++; - return SUCCEEDED(device_->StretchRect(srcSurf, &srcRect, dstSurf, &dstRect, filter == FB_BLIT_LINEAR ? D3DTEXF_LINEAR : D3DTEXF_POINT)); + return SUCCEEDED(device_->StretchRect(srcSurf, &srcRect, dstSurf, &dstRect, (filter == FB_BLIT_LINEAR && channelBits == FB_COLOR_BIT) ? D3DTEXF_LINEAR : D3DTEXF_POINT)); } void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, void *param2) { diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index e61cb93aae..b48d900ab1 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -541,7 +541,9 @@ OpenGLContext::OpenGLContext() { caps_.preferredDepthBufferFormat = DataFormat::D24_S8; caps_.texture3DSupported = true; } - caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object; + + caps_.framebufferCopySupported = gl_extensions.OES_copy_image || gl_extensions.NV_copy_image || gl_extensions.EXT_copy_image || gl_extensions.ARB_copy_image; + caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3; caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported; caps_.depthClampSupported = gl_extensions.ARB_depth_clamp; if (gl_extensions.IsGLES) { diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 06bca64a33..e2cae4c906 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -578,7 +578,7 @@ static int GetBpp(VkFormat format) { } } -VkFormat DataFormatToVulkan(DataFormat format) { +static VkFormat DataFormatToVulkan(DataFormat format) { switch (format) { case DataFormat::D16: return VK_FORMAT_D16_UNORM; case DataFormat::D32F: return VK_FORMAT_D32_SFLOAT; @@ -774,6 +774,8 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) : vulkan_(vulkan), renderManager_(vulkan) { shaderLanguageDesc_.Init(GLSL_VULKAN); + VkFormat depthStencilFormat = vulkan->GetDeviceInfo().preferredDepthStencilFormat; + caps_.anisoSupported = vulkan->GetDeviceFeatures().enabled.samplerAnisotropy != 0; caps_.geometryShaderSupported = vulkan->GetDeviceFeatures().enabled.geometryShader != 0; caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.tessellationShader != 0; @@ -784,8 +786,9 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) caps_.cullDistanceSupported = vulkan->GetDeviceFeatures().enabled.shaderCullDistance != 0; caps_.framebufferBlitSupported = true; caps_.framebufferCopySupported = true; - caps_.framebufferDepthBlitSupported = false; // Can be checked for. + caps_.framebufferDepthBlitSupported = vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat; caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case. + caps_.framebufferSeparateDepthCopySupported = true; // Will pretty much always be the case. caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. caps_.texture3DSupported = true; @@ -1440,18 +1443,24 @@ uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const { VkFormatProperties properties; vkGetPhysicalDeviceFormatProperties(vulkan_->GetCurrentPhysicalDevice(), vulkan_format, &properties); uint32_t flags = 0; - if (properties.optimalTilingFeatures & VkFormatFeatureFlagBits::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { + if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { flags |= FMT_RENDERTARGET; } - if (properties.optimalTilingFeatures & VkFormatFeatureFlagBits::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { + if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { flags |= FMT_DEPTHSTENCIL; } - if (properties.optimalTilingFeatures & VkFormatFeatureFlagBits::VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { + if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { flags |= FMT_TEXTURE; } - if (properties.bufferFeatures & VkFormatFeatureFlagBits::VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) { + if (properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) { flags |= FMT_INPUTLAYOUT; } + if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) && (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) { + flags |= FMT_BLIT; + } + if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) { + flags |= FMT_STORAGE_IMAGE; + } return flags; } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 55093b83d0..9a618df79e 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -202,6 +202,8 @@ enum FormatSupport { FMT_INPUTLAYOUT = 4, FMT_DEPTHSTENCIL = 8, FMT_AUTOGEN_MIPS = 16, + FMT_BLIT = 32, + FMT_STORAGE_IMAGE = 64, }; enum InfoField { @@ -530,6 +532,7 @@ struct DeviceCaps { bool framebufferCopySupported; bool framebufferBlitSupported; bool framebufferDepthCopySupported; + bool framebufferSeparateDepthCopySupported; bool framebufferDepthBlitSupported; bool framebufferFetchSupported; bool texture3DSupported; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 1471f6bcf5..46b8255ea5 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -581,15 +581,16 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir int w = std::min(src->renderWidth, dst->renderWidth); int h = std::min(src->renderHeight, dst->renderHeight); - // Note: We prefer Blit ahead of Copy here, since at least on GL, Copy will always also copy stencil which we don't want. - // See #9740. - // TODO: This ordering should probably apply to GL only, since in Vulkan you can totally copy just the depth aspect. - if (gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT_TO_DEPTH)) { - draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth"); - RebindFramebuffer("After BlitFramebufferDepth"); - } else if (gstate_c.Supports(GPU_SUPPORTS_COPY_IMAGE)) { + // TODO: It might even be advantageous on some GPUs to do this copy using a fragment shader that writes to Z, that way upcoming commands can just continue that render pass. + + // Some GPUs can copy depth but only if stencil gets to come along for the ride. We only want to use this if there is no blit functionality. + if (draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported || !draw_->GetDeviceCaps().framebufferDepthBlitSupported) { draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, w, h, 1, Draw::FB_DEPTH_BIT, "BlitFramebufferDepth"); RebindFramebuffer("After BlitFramebufferDepth"); + } else if (draw_->GetDeviceCaps().framebufferDepthBlitSupported) { + // We'll accept whether we get a separate depth blit or not... + draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth"); + RebindFramebuffer("After BlitFramebufferDepth"); } dst->last_frame_depth_updated = gpuStats.numFlips; } @@ -693,7 +694,7 @@ void FramebufferManagerCommon::ReinterpretFramebuffer(VirtualFramebuffer *vfb, G bool doReinterpret = PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && (lang == HLSL_D3D11 || lang == GLSL_VULKAN || lang == GLSL_3xx); // Copy image required for now. - if (!gstate_c.Supports(GPU_SUPPORTS_COPY_IMAGE)) + if (!draw_->GetDeviceCaps().framebufferCopySupported) doReinterpret = false; if (!doReinterpret) { // Fake reinterpret - just clear the way we always did on Vulkan. Just clear color and stencil. diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index f02d93547e..ba68c1bd4d 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -139,7 +139,6 @@ void GPU_D3D11::CheckGPUFeatures() { } } - features |= GPU_SUPPORTS_COPY_IMAGE; features |= GPU_SUPPORTS_TEXTURE_FLOAT; features |= GPU_SUPPORTS_INSTANCE_RENDERING; features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 57937cd9a8..4be07ecb42 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -185,10 +185,6 @@ void GPU_GLES::CheckGPUFeatures() { } } - if (gl_extensions.ARB_framebuffer_object || gl_extensions.NV_framebuffer_blit || gl_extensions.GLES3) { - features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT | GPU_SUPPORTS_FRAMEBUFFER_BLIT_TO_DEPTH; - } - if ((gl_extensions.gpuVendor == GPU_VENDOR_NVIDIA) || (gl_extensions.gpuVendor == GPU_VENDOR_AMD)) features |= GPU_PREFER_REVERSE_COLOR_ORDER; @@ -198,9 +194,6 @@ void GPU_GLES::CheckGPUFeatures() { if (gl_extensions.EXT_blend_minmax) features |= GPU_SUPPORTS_BLEND_MINMAX; - if (gl_extensions.OES_copy_image || gl_extensions.NV_copy_image || gl_extensions.EXT_copy_image || gl_extensions.ARB_copy_image) - features |= GPU_SUPPORTS_COPY_IMAGE; - if (!gl_extensions.IsGLES) features |= GPU_SUPPORTS_LOGIC_OP; diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 4c35fb4967..665f534137 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -158,7 +158,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, StencilUplo shaderManager_->DirtyLastShader(); - bool useBlit = gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT); + bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported; // Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x. // Then after we're done, we'll just blit it across and stretch it there. diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 2d8db478b9..bc0ede6d1c 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -479,15 +479,13 @@ enum { GPU_SUPPORTS_32BIT_INT_FSHADER = FLAG_BIT(15), GPU_SUPPORTS_DEPTH_TEXTURE = FLAG_BIT(16), GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17), - // Free bit: 18 - GPU_SUPPORTS_COPY_IMAGE = FLAG_BIT(19), + // Free bits: 18-19 GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20), GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21), GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22), GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer GPU_SUPPORTS_TEXTURE_LOD_CONTROL = FLAG_BIT(24), - GPU_SUPPORTS_FRAMEBUFFER_BLIT = FLAG_BIT(26), - GPU_SUPPORTS_FRAMEBUFFER_BLIT_TO_DEPTH = FLAG_BIT(27), + // Free bits: 25-27 GPU_SUPPORTS_TEXTURE_NPOT = FLAG_BIT(28), GPU_SUPPORTS_CLIP_DISTANCE = FLAG_BIT(29), GPU_SUPPORTS_CULL_DISTANCE = FLAG_BIT(30), diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 96c2841f3d..8b6b980f5e 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -232,19 +232,13 @@ void GPU_Vulkan::CheckGPUFeatures() { // Mandatory features on Vulkan, which may be checked in "centralized" code features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT; features |= GPU_SUPPORTS_BLEND_MINMAX; - features |= GPU_SUPPORTS_COPY_IMAGE; features |= GPU_SUPPORTS_TEXTURE_NPOT; features |= GPU_SUPPORTS_INSTANCE_RENDERING; features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH; features |= GPU_SUPPORTS_TEXTURE_FLOAT; features |= GPU_SUPPORTS_DEPTH_TEXTURE; - if (vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat) { - features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT_TO_DEPTH; - } - auto &enabledFeatures = vulkan->GetDeviceFeatures().enabled; if (enabledFeatures.depthClamp) { features |= GPU_SUPPORTS_DEPTH_CLAMP; From 770cb49f9464af00ef6c3baf581f0fd001e26388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 Aug 2022 23:21:41 +0200 Subject: [PATCH 02/35] GLES: FramebufferBlit: Don't blit if the target is the current framebuffer. --- GPU/GLES/FramebufferManagerGLES.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 5a14ff051e..983e3dc7c4 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -257,7 +257,13 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, return; } - bool useBlit = gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT); + bool useBlit = draw_->GetDeviceCaps().framebufferBlitSupported; + bool useCopy = draw_->GetDeviceCaps().framebufferCopySupported; + if (dst == currentRenderVfb_) { + // If already bound, using either a blit or a copy is unlikely to be an optimization. + useBlit = false; + useCopy = false; + } float srcXFactor = useBlit ? src->renderScaleFactor : 1.0f; float srcYFactor = useBlit ? src->renderScaleFactor : 1.0f; @@ -287,7 +293,7 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, return; } - if (gstate_c.Supports(GPU_SUPPORTS_COPY_IMAGE)) { + if (useCopy && draw_->GetDeviceCaps().framebufferCopySupported) { // glBlitFramebuffer can clip, but glCopyImageSubData is more restricted. // In case the src goes outside, we just skip the optimization in that case. const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1; @@ -304,8 +310,7 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, if (useBlit) { draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); } else { - // TODO: Move this workaround out into thin3d, instead of dirtying up the code here. - + // TODO: Use thin3d for this, instead of dirtying up the code here. draw_->BindFramebufferAsRenderTarget(dst->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); draw_->BindFramebufferAsTexture(src->fbo, 0, Draw::FB_COLOR_BIT, 0); From d4d92e39ffd5465d1153bb8b82d65ca255c17897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 2 Aug 2022 23:31:02 +0200 Subject: [PATCH 03/35] Implement DrawUP for D3D11 This is so we can do simple drawing without buffer management through thin3d on all backends. --- Common/GPU/D3D11/thin3d_d3d11.cpp | 18 ++++++++++++++---- Common/GPU/D3D9/thin3d_d3d9.cpp | 3 --- Common/GPU/OpenGL/thin3d_gl.cpp | 7 ------- Common/GPU/Vulkan/thin3d_vulkan.cpp | 3 --- Common/GPU/thin3d.h | 1 - Common/Render/DrawBuffer.cpp | 19 +------------------ Common/Render/DrawBuffer.h | 1 - 7 files changed, 15 insertions(+), 37 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index a9a922cf24..7dc6e7e17c 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -38,6 +38,7 @@ class D3D11Pipeline; class D3D11BlendState; class D3D11DepthStencilState; class D3D11SamplerState; +class D3D11Buffer; class D3D11RasterState; class D3D11Framebuffer; @@ -252,6 +253,7 @@ private: // Temporaries ID3D11Texture2D *packTexture_ = nullptr; + Buffer *upBuffer_ = nullptr; // System info D3D_FEATURE_LEVEL featureLevel_; @@ -338,9 +340,14 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de _assert_(SUCCEEDED(hr)); shaderLanguageDesc_.Init(HLSL_D3D11); + + const size_t UP_MAX_BYTES = 65536 * 24; + + upBuffer_ = CreateBuffer(UP_MAX_BYTES, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); } D3D11DrawContext::~D3D11DrawContext() { + upBuffer_->Release(); packTexture_->Release(); // Release references. @@ -756,9 +763,6 @@ public: shaderModule->Release(); } } - bool RequiresBuffer() override { - return true; - } AutoRef input; ID3D11InputLayout *il = nullptr; @@ -1248,7 +1252,13 @@ void D3D11DrawContext::DrawIndexed(int indexCount, int offset) { void D3D11DrawContext::DrawUP(const void *vdata, int vertexCount) { ApplyCurrentState(); - // TODO: Upload the data then draw.. + + int byteSize = vertexCount * curPipeline_->input->strides[0]; + + UpdateBuffer(upBuffer_, (const uint8_t *)vdata, 0, byteSize, Draw::UPDATE_DISCARD); + BindVertexBuffers(0, 1, &upBuffer_, nullptr); + int offset = 0; + Draw(vertexCount, offset); } uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const { diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 684b727cc5..d42833558a 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -272,9 +272,6 @@ public: D3D9Pipeline() {} ~D3D9Pipeline() { } - bool RequiresBuffer() override { - return false; - } D3D9ShaderModule *vshader; D3D9ShaderModule *pshader; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index b48d900ab1..f25fe16ef9 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -261,9 +261,6 @@ public: ~OpenGLInputLayout(); void Compile(const InputLayoutDesc &desc); - bool RequiresBuffer() { - return false; - } GLRInputLayout *inputLayout_ = nullptr; int stride = 0; @@ -284,10 +281,6 @@ public: bool LinkShaders(); - bool RequiresBuffer() override { - return inputLayout && inputLayout->RequiresBuffer(); - } - GLuint prim = 0; std::vector shaders; AutoRef inputLayout; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index e2cae4c906..2e329f1d45 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -271,9 +271,6 @@ public: int GetUBOSize() const { return uboSize_; } - bool RequiresBuffer() override { - return false; - } VkPipeline backbufferPipeline = VK_NULL_HANDLE; VkPipeline framebufferPipeline = VK_NULL_HANDLE; diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 9a618df79e..185d8929fc 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -450,7 +450,6 @@ public: class Pipeline : public RefCountedObject { public: virtual ~Pipeline() {} - virtual bool RequiresBuffer() = 0; }; class RasterState : public RefCountedObject {}; diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 35e3f0176b..9b09e7675b 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -32,12 +32,6 @@ void DrawBuffer::Init(Draw::DrawContext *t3d, Draw::Pipeline *pipeline) { draw_ = t3d; inited_ = true; - - if (pipeline->RequiresBuffer()) { - vbuf_ = draw_->CreateBuffer(MAX_VERTS * sizeof(Vertex), BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); - } else { - vbuf_ = nullptr; - } } Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *t3d) { @@ -57,10 +51,6 @@ Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *t3d) { } void DrawBuffer::Shutdown() { - if (vbuf_) { - vbuf_->Release(); - vbuf_ = nullptr; - } inited_ = false; alphaStack_.clear(); drawMatrixStack_.clear(); @@ -90,14 +80,7 @@ void DrawBuffer::Flush(bool set_blend_state) { ub.tint = tint_; ub.saturation = saturation_; draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); - if (vbuf_) { - draw_->UpdateBuffer(vbuf_, (const uint8_t *)verts_, 0, sizeof(Vertex) * count_, Draw::UPDATE_DISCARD); - draw_->BindVertexBuffers(0, 1, &vbuf_, nullptr); - int offset = 0; - draw_->Draw(count_, offset); - } else { - draw_->DrawUP((const void *)verts_, count_); - } + draw_->DrawUP((const void *)verts_, count_); count_ = 0; } diff --git a/Common/Render/DrawBuffer.h b/Common/Render/DrawBuffer.h index e103805d2e..4a29893c15 100644 --- a/Common/Render/DrawBuffer.h +++ b/Common/Render/DrawBuffer.h @@ -199,7 +199,6 @@ private: std::vector alphaStack_; Draw::DrawContext *draw_ = nullptr; - Draw::Buffer *vbuf_ = nullptr; Draw::Pipeline *pipeline_ = nullptr; Vertex *verts_; From 9bead443c399fc6bbaf3f91077b8ed8f301fc105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 20 Jul 2022 11:09:32 +0200 Subject: [PATCH 04/35] Unify stencil buffer upload using Draw. Only OpenGL tested yet (shaders need adaptation). --- CMakeLists.txt | 4 - Common/GPU/D3D11/thin3d_d3d11.cpp | 1 + Common/GPU/OpenGL/thin3d_gl.cpp | 2 +- Common/GPU/thin3d.h | 8 +- GPU/Common/FramebufferManagerCommon.cpp | 4 + GPU/Common/FramebufferManagerCommon.h | 9 +- GPU/Common/StencilCommon.cpp | 264 +++++++++++++++++++++++- GPU/Common/StencilCommon.h | 4 - GPU/D3D11/FramebufferManagerD3D11.h | 2 - GPU/D3D11/StencilBufferD3D11.cpp | 245 ---------------------- GPU/Directx9/FramebufferManagerDX9.h | 2 - GPU/Directx9/StencilBufferDX9.cpp | 259 ----------------------- GPU/GLES/FramebufferManagerGLES.cpp | 8 +- GPU/GLES/FramebufferManagerGLES.h | 6 +- GPU/GPU.vcxproj | 11 +- GPU/GPU.vcxproj.filters | 14 +- GPU/Vulkan/FramebufferManagerVulkan.h | 2 - GPU/Vulkan/StencilBufferVulkan.cpp | 229 -------------------- android/jni/Android.mk | 1 - libretro/Makefile.common | 4 - 20 files changed, 287 insertions(+), 792 deletions(-) delete mode 100644 GPU/D3D11/StencilBufferD3D11.cpp delete mode 100644 GPU/Directx9/StencilBufferDX9.cpp delete mode 100644 GPU/Vulkan/StencilBufferVulkan.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ecfece342d..670e5f437c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1455,7 +1455,6 @@ set(GPU_GLES GPU/GLES/ShaderManagerGLES.h GPU/GLES/StateMappingGLES.cpp GPU/GLES/StateMappingGLES.h - GPU/GLES/StencilBufferGLES.cpp GPU/GLES/TextureCacheGLES.cpp GPU/GLES/TextureCacheGLES.h GPU/GLES/DrawEngineGLES.cpp @@ -1479,7 +1478,6 @@ set(GPU_VULKAN GPU/Vulkan/ShaderManagerVulkan.h GPU/Vulkan/StateMappingVulkan.cpp GPU/Vulkan/StateMappingVulkan.h - GPU/Vulkan/StencilBufferVulkan.cpp GPU/Vulkan/TextureCacheVulkan.cpp GPU/Vulkan/TextureCacheVulkan.h GPU/Vulkan/VulkanUtil.cpp @@ -1499,7 +1497,6 @@ set(GPU_D3D9 GPU/Directx9/ShaderManagerDX9.h GPU/Directx9/StateMappingDX9.cpp GPU/Directx9/StateMappingDX9.h - GPU/Directx9/StencilBufferDX9.cpp GPU/Directx9/TextureCacheDX9.cpp GPU/Directx9/TextureCacheDX9.h ) @@ -1519,7 +1516,6 @@ set(GPU_D3D11 GPU/D3D11/ShaderManagerD3D11.h GPU/D3D11/StateMappingD3D11.cpp GPU/D3D11/StateMappingD3D11.h - GPU/D3D11/StencilBufferD3D11.cpp GPU/D3D11/TextureCacheD3D11.cpp GPU/D3D11/TextureCacheD3D11.h ) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 7dc6e7e17c..d3a33d85fe 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -249,6 +249,7 @@ private: uint8_t stencilRef_ = 0; uint8_t stencilWriteMask_ = 0xFF; uint8_t stencilCompareMask_ = 0xFF; + bool stencilDirty_ = true; // Temporaries diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index f25fe16ef9..77e1d822cc 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -1112,7 +1112,7 @@ void OpenGLContext::ApplySamplers() { const OpenGLSamplerState *samp = boundSamplers_[i]; const GLRTexture *tex = boundTextures_[i]; if (tex) { - _assert_(samp); + _assert_msg_(samp, "Sampler missing"); } else { continue; } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 185d8929fc..c832d6cc2e 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -25,7 +25,7 @@ namespace Draw { // Useful in UBOs typedef int bool32; -enum class Comparison : int { +enum class Comparison : uint8_t { NEVER, LESS, EQUAL, @@ -37,7 +37,7 @@ enum class Comparison : int { }; // Had to prefix with LOGIC, too many clashes -enum class LogicOp : int { +enum class LogicOp : uint8_t { LOGIC_CLEAR, LOGIC_SET, LOGIC_COPY, @@ -56,7 +56,7 @@ enum class LogicOp : int { LOGIC_OR_INVERTED, }; -enum class BlendOp : int { +enum class BlendOp : uint8_t { ADD, SUBTRACT, REV_SUBTRACT, @@ -96,7 +96,7 @@ enum class StencilOp { DECREMENT_AND_WRAP = 7, }; -enum class TextureFilter : int { +enum class TextureFilter : uint8_t { NEAREST = 0, LINEAR = 1, }; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 46b8255ea5..6d7f0446ee 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2488,6 +2488,10 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(reinterpretVBuf_); DoRelease(reinterpretSampler_); DoRelease(reinterpretVS_); + DoRelease(stencilUploadFs_); + DoRelease(stencilUploadVs_); + DoRelease(stencilUploadSampler_); + DoRelease(stencilUploadPipeline_); presentation_->DeviceLost(); draw_ = nullptr; } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 04e2683e0f..18e99fd559 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -253,7 +253,7 @@ public: void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt); void UpdateFromMemory(u32 addr, int size, bool safe); void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor); - virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) = 0; + bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR); // Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it. // In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless // read framebuffers is on, in which case this should always return false). @@ -467,4 +467,11 @@ protected: Draw::ShaderModule *reinterpretVS_ = nullptr; Draw::SamplerState *reinterpretSampler_ = nullptr; Draw::Buffer *reinterpretVBuf_ = nullptr; + + // Common implementation of stencil buffer upload. Also not 100% optimal, but not perforamnce + // critical either. + Draw::Pipeline *stencilUploadPipeline_ = nullptr; + Draw::ShaderModule *stencilUploadVs_ = nullptr; + Draw::ShaderModule *stencilUploadFs_ = nullptr; + Draw::SamplerState *stencilUploadSampler_ = nullptr; }; diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 29af15c020..94b7373952 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -15,9 +15,18 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/GPU/Shader.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" +#include "Core/Config.h" +#include "Core/ConfigValues.h" +#include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" +#include "GPU/GLES/DrawEngineGLES.h" +#include "GPU/GLES/FramebufferManagerGLES.h" +#include "GPU/GLES/ShaderManagerGLES.h" +#include "GPU/GLES/TextureCacheGLES.h" -u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { +static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { const u32 *ptr = (const u32 *)ptr8; for (u32 i = 0; i < numPixels / 2; ++i) { @@ -28,7 +37,7 @@ u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { return 0; } -u8 StencilBits4444(const u8 *ptr8, u32 numPixels) { +static u8 StencilBits4444(const u8 *ptr8, u32 numPixels) { const u32 *ptr = (const u32 *)ptr8; u32 bits = 0; @@ -39,7 +48,7 @@ u8 StencilBits4444(const u8 *ptr8, u32 numPixels) { return ((bits >> 12) & 0xF) | (bits >> 28); } -u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { +static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { const u32 *ptr = (const u32 *)ptr8; u32 bits = 0; @@ -49,3 +58,252 @@ u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { return bits >> 24; } + +struct StencilUB { + float stencilValue; +}; + +const UniformBufferDesc stencilUBDesc { sizeof(StencilUB), { + { "stencilValue", 0, -1, UniformType::FLOAT1, 0 }, +} }; + +static const char *stencil_fs = R"( +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; // just hope it's enough.. +#endif +#endif +#if __VERSION__ >= 130 +#define varying in +#define texture2D texture +#define gl_FragColor fragColor0 +out vec4 fragColor0; +#endif +varying vec2 v_texcoord0; +uniform float stencilValue; +uniform sampler2D tex; +float roundAndScaleTo255f(in float x) { return floor(x * 255.99); } +void main() { + vec4 index = texture2D(tex, v_texcoord0); + gl_FragColor = vec4(v_texcoord0.x, v_texcoord0.y, 0.0, index.a); + float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue); + // Bitwise operations on floats, ugh. + if (mod(floor(shifted), 2.0) < 0.99) discard; +} +)"; + +static const char *stencil_vs = R"( +#ifdef GL_ES +precision highp float; +#endif +#if __VERSION__ >= 130 +#define attribute in +#define varying out +#endif +attribute vec2 a_position; +varying vec2 v_texcoord0; +void main() { + v_texcoord0 = a_position * 2.0; // yes, this should be right. Should be 2.0 in the far corners. + gl_Position = vec4(v_texcoord0 * 2.0 - vec2(1.0, 1.0), 0.0, 1.0); +} +)"; + + +static const std::vector fsStencilSources = { + {ShaderLanguage::GLSL_1xx, stencil_fs} +}; + +static const std::vector vsStencilSources = { + {ShaderLanguage::GLSL_1xx, stencil_vs} +}; + +bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { + using namespace Draw; + + addr &= 0x3FFFFFFF; + if (!MayIntersectFramebuffer(addr)) { + return false; + } + + VirtualFramebuffer *dstBuffer = 0; + for (size_t i = 0; i < vfbs_.size(); ++i) { + VirtualFramebuffer *vfb = vfbs_[i]; + if (vfb->fb_address == addr) { + dstBuffer = vfb; + } + } + if (!dstBuffer) { + return false; + } + + int values = 0; + u8 usedBits = 0; + + const u8 *src = Memory::GetPointer(addr); + if (!src) + return false; + + switch (dstBuffer->format) { + case GE_FORMAT_565: + // Well, this doesn't make much sense. + return false; + case GE_FORMAT_5551: + usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 2; + break; + case GE_FORMAT_4444: + usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 16; + break; + case GE_FORMAT_8888: + usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 256; + break; + case GE_FORMAT_INVALID: + case GE_FORMAT_DEPTH16: + // Inconceivable. + _assert_(false); + break; + } + + if (usedBits == 0) { + if (flags == StencilUpload::STENCIL_IS_ZERO) { + // Common when creating buffers, it's already 0. We're done. + return false; + } + shaderManager_->DirtyLastShader(); + + // Let's not bother with the shader if it's just zero. + if (dstBuffer->fbo) { + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "NotifyStencilUpload_Clear"); + } + + // Clear destination alpha. + // render_->Clear(0, 0, 0, GL_COLOR_BUFFER_BIT, 0x8, 0, 0, 0, 0); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE); + return true; + } + + shaderManager_->DirtyLastShader(); + textureCache_->ForgetLastTexture(); + + if (!stencilUploadPipeline_) { + stencilUploadFs_ = CreateShader(draw_, ShaderStage::Fragment, fsStencilSources); + stencilUploadVs_ = CreateShader(draw_, ShaderStage::Vertex, vsStencilSources); + + _assert_(stencilUploadFs_ && stencilUploadVs_); + + InputLayoutDesc desc = { + { + { 8, false }, + }, + { + { 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 }, + }, + }; + InputLayout *inputLayout = draw_->CreateInputLayout(desc); + + BlendState *blendOff = draw_->CreateBlendState({ false, 0x8 }); + DepthStencilStateDesc dsDesc{}; + dsDesc.stencilEnabled = true; + dsDesc.stencil.compareOp = Comparison::ALWAYS; + dsDesc.stencil.depthFailOp = StencilOp::REPLACE; + dsDesc.stencil.failOp = StencilOp::REPLACE; + dsDesc.stencil.passOp = StencilOp::REPLACE; + DepthStencilState *stencilWrite = draw_->CreateDepthStencilState(dsDesc); + RasterState *rasterNoCull = draw_->CreateRasterState({}); + + PipelineDesc stencilWriteDesc{ + Primitive::TRIANGLE_LIST, + { stencilUploadVs_, stencilUploadFs_ }, + inputLayout, stencilWrite, blendOff, rasterNoCull, &stencilUBDesc, + }; + stencilUploadPipeline_ = draw_->CreateGraphicsPipeline(stencilWriteDesc); + _assert_(stencilUploadPipeline_); + + rasterNoCull->Release(); + blendOff->Release(); + stencilWrite->Release(); + inputLayout->Release(); + + SamplerStateDesc descNearest{}; + stencilUploadSampler_ = draw_->CreateSamplerState(descNearest); + } + + // Fullscreen triangle + const float positions[6] = { + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + }; + + bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported; + + // Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x. + // Then after we're done, we'll just blit it across and stretch it there. Not worth doing + // if already at 1x size though, of course. + if (dstBuffer->width == dstBuffer->renderWidth || !dstBuffer->fbo) { + useBlit = false; + } + + u16 w = useBlit ? dstBuffer->width : dstBuffer->renderWidth; + u16 h = useBlit ? dstBuffer->height : dstBuffer->renderHeight; + + Draw::Framebuffer *blitFBO = nullptr; + if (useBlit) { + blitFBO = GetTempFBO(TempFBO::STENCIL, w, h); + draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "NotifyStencilUpload_Blit"); + } else if (dstBuffer->fbo) { + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "NotifyStencilUpload_NoBlit"); + } + + Draw::Viewport viewport = { 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }; + draw_->SetViewports(1, &viewport); + + // TODO: Switch the format to a single channel format? + Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstBuffer->height); + if (!tex) { + // Bad! + return false; + } + + draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); + draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &stencilUploadSampler_); + + // We must bind the program after starting the render pass, and set the color mask after clearing. + draw_->SetScissorRect(0, 0, w, h); + draw_->BindPipeline(stencilUploadPipeline_); + + for (int i = 1; i < values; i += i) { + if (!(usedBits & i)) { + // It's already zero, let's skip it. + continue; + } + StencilUB ub; + if (dstBuffer->format == GE_FORMAT_4444) { + draw_->SetStencilParams(0xFF, (i << 4) | i, 0xFF); + ub.stencilValue = i * (16.0f / 255.0f); + } else if (dstBuffer->format == GE_FORMAT_5551) { + draw_->SetStencilParams(0xFF, 0xFF, 0xFF); + ub.stencilValue = i * (128.0f / 255.0f); + } else { + draw_->SetStencilParams(0xFF, i, 0xFF); + ub.stencilValue = i * (1.0f / 255.0f); + } + draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); + draw_->DrawUP(positions, 3); + } + + if (useBlit) { + // Note that scissors don't affect blits on other APIs than OpenGL, so might want to try to get rid of this. + draw_->SetScissorRect(0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight); + draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST, "NotifyStencilUpload_Blit"); + } + + tex->Release(); + RebindFramebuffer("RebindFramebuffer - Stencil"); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + return true; +} diff --git a/GPU/Common/StencilCommon.h b/GPU/Common/StencilCommon.h index ee26b4412e..3a22336b5f 100644 --- a/GPU/Common/StencilCommon.h +++ b/GPU/Common/StencilCommon.h @@ -1,7 +1,3 @@ #pragma once #include "Common/CommonTypes.h" - -u8 StencilBits8888(const u8 *ptr8, u32 numPixels); -u8 StencilBits4444(const u8 *ptr8, u32 numPixels); -u8 StencilBits5551(const u8 *ptr8, u32 numPixels); diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 0a389f6dc3..db843c1a02 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -43,8 +43,6 @@ public: void EndFrame(); - virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; - // TODO: Remove ID3D11Buffer *GetDynamicQuadBuffer() { return quadBuffer_; diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp deleted file mode 100644 index eee531b55f..0000000000 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) 2014- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include - -#include "Common/GPU/thin3d.h" - -#include "Common/Log.h" -#include "Core/Reporting.h" -#include "GPU/Common/StencilCommon.h" -#include "GPU/D3D11/FramebufferManagerD3D11.h" -#include "GPU/D3D11/ShaderManagerD3D11.h" -#include "GPU/D3D11/TextureCacheD3D11.h" -#include "GPU/D3D11/D3D11Util.h" - -struct StencilValueUB { - uint32_t u_stencilValue[4]; -}; - -static const char *stencil_ps = R"( -SamplerState samp : register(s0); -Texture2D tex : register(t0); -cbuffer base : register(b0) { - int4 u_stencilValue; -}; -struct PS_IN { - float2 v_texcoord0 : TEXCOORD0; -}; -float4 main(PS_IN In) : SV_Target { - float4 index = tex.Sample(samp, In.v_texcoord0); - int indexBits = int(index.a * 255.99); - if ((indexBits & u_stencilValue.x) == 0) - discard; - return index.aaaa; -} -)"; - -// static const char *stencil_ps_fast; - -static const char *stencil_vs = R"( -struct VS_IN { - float4 a_position : POSITION; - float2 a_texcoord0 : TEXCOORD0; -}; -struct VS_OUT { - float2 v_texcoord0 : TEXCOORD0; - float4 position : SV_Position; -}; -VS_OUT main(VS_IN In) { - VS_OUT Out; - Out.position = In.a_position; - Out.v_texcoord0 = In.a_texcoord0; - return Out; -} -)"; - -// TODO : If SV_StencilRef is available (D3D11.3) then this can be done in a single pass. -bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { - addr &= 0x3FFFFFFF; - if (!MayIntersectFramebuffer(addr)) { - return false; - } - - VirtualFramebuffer *dstBuffer = 0; - for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebuffer *vfb = vfbs_[i]; - if (vfb->fb_address == addr) { - dstBuffer = vfb; - } - } - if (!dstBuffer) { - return false; - } - - int values = 0; - u8 usedBits = 0; - - const u8 *src = Memory::GetPointer(addr); - if (!src) { - return false; - } - - switch (dstBuffer->format) { - case GE_FORMAT_565: - // Well, this doesn't make much sense. - return false; - case GE_FORMAT_5551: - usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 2; - break; - case GE_FORMAT_4444: - usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 16; - break; - case GE_FORMAT_8888: - usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 256; - break; - case GE_FORMAT_INVALID: - // Impossible. - break; - } - - if (usedBits == 0) { - if (flags == StencilUpload::STENCIL_IS_ZERO) { - // Common when creating buffers, it's already 0. We're done. - return false; - } - - // Clear stencil+alpha but not color. Only way is to draw a quad. - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); - context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0); - context_->IASetVertexBuffers(0, 1, &fsQuadBuffer_, &quadStride_, &quadOffset_); - context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context_->Draw(4, 0); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE); - return true; - } - - // TODO: Helper with logging? - if (!stencilUploadPS_) { - std::string errorMessage; - stencilUploadPS_ = CreatePixelShaderD3D11(device_, stencil_ps, strlen(stencil_ps), featureLevel_); - } - if (!stencilUploadVS_) { - std::string errorMessage; - std::vector byteCode; - stencilUploadVS_ = CreateVertexShaderD3D11(device_, stencil_vs, strlen(stencil_vs), &byteCode, featureLevel_); - ASSERT_SUCCESS(device_->CreateInputLayout(g_QuadVertexElements, 2, byteCode.data(), byteCode.size(), &stencilUploadInputLayout_)); - } - if (!stencilValueBuffer_) { - D3D11_BUFFER_DESC desc{}; - desc.ByteWidth = sizeof(StencilValueUB); - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &stencilValueBuffer_)); - } - - shaderManager_->DirtyLastShader(); - - u16 w = dstBuffer->renderWidth; - u16 h = dstBuffer->renderHeight; - Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); - if (!tex) - return false; - if (dstBuffer->fbo) { - // Typically, STENCIL_IS_ZERO means it's already bound. - Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR; - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction }, "Stencil"); - } else { - // something is wrong... - } - D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }; - context_->RSSetViewports(1, &vp); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); - - float coord[20] = { - -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0, 0.0f, - -1.0f, -1.0f, 0.0f, 0.0f, 1.0, - 1.0f, -1.0f, 0.0f, 1.0, 1.0, - }; - - D3D11_MAPPED_SUBRESOURCE map; - context_->Map(quadBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, coord, sizeof(float) * 4 * 5); - context_->Unmap(quadBuffer_, 0); - - shaderManager_->DirtyLastShader(); - textureCache_->ForgetLastTexture(); - - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF); - context_->IASetInputLayout(stencilUploadInputLayout_); - context_->PSSetShader(stencilUploadPS_, nullptr, 0); - context_->VSSetShader(stencilUploadVS_, nullptr, 0); - draw_->BindTextures(0, 1, &tex); - context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context_->IASetVertexBuffers(0, 1, &quadBuffer_, &quadStride_, &quadOffset_); - context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DClamp); - context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); - - for (int i = 1; i < values; i += i) { - if (!(usedBits & i)) { - // It's already zero, let's skip it. - continue; - } - uint8_t mask = 0; - uint8_t value = 0; - if (dstBuffer->format == GE_FORMAT_4444) { - mask = i | (i << 4); - value = i * 16; - } else if (dstBuffer->format == GE_FORMAT_5551) { - mask = 0xFF; - value = i * 128; - } else { - mask = i; - value = i; - } - if (!stencilMaskStates_[mask]) { - D3D11_DEPTH_STENCIL_DESC desc{}; - desc.DepthEnable = false; - desc.StencilEnable = true; - desc.StencilReadMask = 0xFF; - desc.StencilWriteMask = mask; - desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; - desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; - desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - desc.BackFace = desc.FrontFace; - device_->CreateDepthStencilState(&desc, &stencilMaskStates_[mask]); - } - context_->OMSetDepthStencilState(stencilMaskStates_[mask], 0xFF); - - D3D11_MAPPED_SUBRESOURCE map; - context_->Map(stencilValueBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - StencilValueUB ub{ (uint32_t)value }; - memcpy(map.pData, &ub, sizeof(ub)); - context_->Unmap(stencilValueBuffer_, 0); - context_->PSSetConstantBuffers(0, 1, &stencilValueBuffer_); - context_->Draw(4, 0); - } - - tex->Release(); - RebindFramebuffer("RebindFramebuffer stencil"); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - return true; -} diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index 0d715d75f1..c8dbbe249a 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -48,8 +48,6 @@ public: void EndFrame(); - virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; - bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; diff --git a/GPU/Directx9/StencilBufferDX9.cpp b/GPU/Directx9/StencilBufferDX9.cpp deleted file mode 100644 index 31ae6aa17d..0000000000 --- a/GPU/Directx9/StencilBufferDX9.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) 2014- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include - -#include "Common/GPU/D3D9/D3D9StateCache.h" -#include "Common/GPU/thin3d.h" -#include "Core/Reporting.h" -#include "GPU/Common/StencilCommon.h" -#include "GPU/Directx9/FramebufferManagerDX9.h" -#include "GPU/Directx9/ShaderManagerDX9.h" -#include "GPU/Directx9/TextureCacheDX9.h" - -namespace DX9 { - -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) - -static const char *stencil_ps = R"( -sampler tex: register(s0); -// TODO: Don't use fixed registers? Or don't overlap? -float4 u_stencilValue : register(c)" STR(CONST_PS_STENCILVALUE) R"(); -struct PS_IN { - float2 v_texcoord0 : TEXCOORD0; -}; -float roundAndScaleTo255f(in float x) { return floor(x * 255.99); } -float4 main(PS_IN In) : COLOR { - float4 index = tex2D(tex, In.v_texcoord0); - float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue.x); - clip(fmod(floor(shifted), 2.0) - 0.99); - return index.aaaa; -} -)"; - -static const char *stencil_vs = R"( -struct VS_IN { - float4 a_position : POSITION; - float2 a_texcoord0 : TEXCOORD0; -}; -struct VS_OUT { - float4 position : POSITION; - float2 v_texcoord0 : TEXCOORD0; -}; -VS_OUT main(VS_IN In) { - VS_OUT Out; - Out.position = In.a_position; - Out.v_texcoord0 = In.a_texcoord0; - return Out; -} -)"; - -bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { - addr &= 0x3FFFFFFF; - if (!MayIntersectFramebuffer(addr)) { - return false; - } - - VirtualFramebuffer *dstBuffer = 0; - for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebuffer *vfb = vfbs_[i]; - if (vfb->fb_address == addr) { - dstBuffer = vfb; - } - } - if (!dstBuffer) { - return false; - } - - int values = 0; - u8 usedBits = 0; - - const u8 *src = Memory::GetPointer(addr); - if (!src) { - return false; - } - - switch (dstBuffer->format) { - case GE_FORMAT_565: - // Well, this doesn't make much sense. - return false; - case GE_FORMAT_5551: - usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 2; - break; - case GE_FORMAT_4444: - usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 16; - break; - case GE_FORMAT_8888: - usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 256; - break; - case GE_FORMAT_INVALID: - // Impossible. - break; - } - - if (usedBits == 0) { - if (flags == StencilUpload::STENCIL_IS_ZERO) { - // Common when creating buffers, it's already 0. We're done. - return false; - } - - // Let's not bother with the shader if it's just zero. - dxstate.scissorTest.disable(); - dxstate.colorMask.set(0x8); - // TODO: Verify this clears only stencil/alpha. - device_->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0, 0, 0, 0), 0.0f, 0); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE); - return true; - } - - if (stencilUploadFailed_) { - return false; - } - - // TODO: Helper with logging? - if (!stencilUploadPS_) { - std::string errorMessage; - bool success = CompilePixelShaderD3D9(device_, stencil_ps, &stencilUploadPS_, &errorMessage); - if (!errorMessage.empty()) { - if (success) { - ERROR_LOG(G3D, "Warnings in shader compilation!"); - } else { - ERROR_LOG(G3D, "Error in shader compilation!"); - } - ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str()); - ERROR_LOG(G3D, "Shader source:\n%s", stencil_ps); - OutputDebugStringUTF8("Messages:\n"); - OutputDebugStringUTF8(errorMessage.c_str()); - Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), stencil_ps); - } - if (!success) { - if (stencilUploadPS_) { - stencilUploadPS_->Release(); - } - stencilUploadPS_ = nullptr; - } - } - if (!stencilUploadVS_) { - std::string errorMessage; - bool success = CompileVertexShaderD3D9(device_, stencil_vs, &stencilUploadVS_, &errorMessage); - if (!errorMessage.empty()) { - if (success) { - ERROR_LOG(G3D, "Warnings in shader compilation!"); - } else { - ERROR_LOG(G3D, "Error in shader compilation!"); - } - ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str()); - ERROR_LOG(G3D, "Shader source:\n%s", stencil_vs); - OutputDebugStringUTF8("Messages:\n"); - OutputDebugStringUTF8(errorMessage.c_str()); - Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), stencil_vs); - } - if (!success) { - if (stencilUploadVS_) { - stencilUploadVS_->Release(); - } - stencilUploadVS_ = nullptr; - } - } - if (!stencilUploadPS_ || !stencilUploadVS_) { - stencilUploadFailed_ = true; - return false; - } - - shaderManager_->DirtyLastShader(); - - dxstate.colorMask.set(0x8); - dxstate.stencilTest.enable(); - dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE); - - u16 w = dstBuffer->renderWidth; - u16 h = dstBuffer->renderHeight; - - if (dstBuffer->fbo) { - // Typically, STENCIL_IS_ZERO means it's already bound. - Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR; - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction }, "StencilUpload"); - } - D3DVIEWPORT9 vp{ 0, 0, w, h, 0.0f, 1.0f }; - device_->SetViewport(&vp); - - Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); - if (!tex) - return false; - - // TODO: Ideally, we should clear alpha to zero here (but not RGB.) - - dxstate.stencilFunc.set(D3DCMP_ALWAYS); - dxstate.stencilRef.set(0xFF); - dxstate.stencilCompareMask.set(0xFF); - - float coord[20] = { - -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, - }; - - device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - - device_->SetVertexDeclaration(pFramebufferVertexDecl); - device_->SetPixelShader(stencilUploadPS_); - device_->SetVertexShader(stencilUploadVS_); - - draw_->BindTextures(0, 1, &tex); - - shaderManager_->DirtyLastShader(); - textureCache_->ForgetLastTexture(); - - for (int i = 1; i < values; i += i) { - if (!(usedBits & i)) { - // It's already zero, let's skip it. - continue; - } - if (dstBuffer->format == GE_FORMAT_4444) { - dxstate.stencilWriteMask.set(i | (i << 4)); - const float f[4] = {i * (16.0f / 255.0f)}; - device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); - } else if (dstBuffer->format == GE_FORMAT_5551) { - dxstate.stencilWriteMask.set(0xFF); - const float f[4] = {i * (128.0f / 255.0f)}; - device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); - } else { - dxstate.stencilWriteMask.set(i); - const float f[4] = {i * (1.0f / 255.0f)}; - device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); - } - HRESULT hr = device_->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coord, 5 * sizeof(float)); - if (FAILED(hr)) { - ERROR_LOG_REPORT(G3D, "Failed to draw stencil bit %x: %08x", i, (uint32_t)hr); - } - } - - tex->Release(); - dxstate.stencilWriteMask.set(0xFF); - dxstate.viewport.restore(); - RebindFramebuffer("RebindFramebuffer stencil"); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - return true; -} - -} // namespace DX9 diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 983e3dc7c4..42245c4d2e 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -144,10 +144,12 @@ void FramebufferManagerGLES::DestroyDeviceObjects() { render_->DeleteProgram(draw2dprogram_); draw2dprogram_ = nullptr; } - if (stencilUploadProgram_) { - render_->DeleteProgram(stencilUploadProgram_); - stencilUploadProgram_ = nullptr; + + if (stencilUploadPipeline_) { + stencilUploadPipeline_->Release(); + stencilUploadPipeline_ = nullptr; } + if (depthDownloadProgram_) { render_->DeleteProgram(depthDownloadProgram_); depthDownloadProgram_ = nullptr; diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 7e558772d2..8347f059a2 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -50,7 +50,7 @@ public: void DeviceLost() override; void DeviceRestore(Draw::DrawContext *draw) override; - bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; + bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR); bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; @@ -76,10 +76,6 @@ private: GLRProgram *draw2dprogram_ = nullptr; - GLRProgram *stencilUploadProgram_ = nullptr; - int u_stencilUploadTex = -1; - int u_stencilValue = -1; - GLRProgram *depthDownloadProgram_ = nullptr; int u_depthDownloadTex = -1; int u_depthDownloadFactor = -1; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 49db8ec9c4..ae899f0cd2 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -513,7 +513,6 @@ - @@ -525,7 +524,6 @@ - @@ -572,12 +570,6 @@ true true - - true - true - true - true - true true @@ -616,7 +608,6 @@ - @@ -675,4 +666,4 @@ - \ No newline at end of file + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 2f26b61aa6..9c8d6b0f93 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -356,9 +356,6 @@ Common - - DirectX9 - Common @@ -416,9 +413,6 @@ GLES - - GLES - GLES @@ -455,9 +449,6 @@ D3D11 - - D3D11 - Common @@ -473,9 +464,6 @@ Debugger - - Vulkan - Common @@ -547,4 +535,4 @@ Shaders - \ No newline at end of file + diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h index 6e8725398a..45a07ef9ed 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -52,8 +52,6 @@ public: void DeviceLost() override; void DeviceRestore(Draw::DrawContext *draw) override; - bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; - // If within a render pass, this will just issue a regular clear. If beginning a new render pass, // do that. void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth); diff --git a/GPU/Vulkan/StencilBufferVulkan.cpp b/GPU/Vulkan/StencilBufferVulkan.cpp deleted file mode 100644 index 6998455aef..0000000000 --- a/GPU/Vulkan/StencilBufferVulkan.cpp +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) 2014- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include "Common/GPU/thin3d.h" -#include "Common/GPU/Vulkan/VulkanRenderManager.h" - -#include "Common/Log.h" -#include "Core/Config.h" -#include "Core/Reporting.h" -#include "GPU/Common/StencilCommon.h" -#include "GPU/Vulkan/FramebufferManagerVulkan.h" -#include "GPU/Vulkan/ShaderManagerVulkan.h" -#include "GPU/Vulkan/TextureCacheVulkan.h" -#include "GPU/Vulkan/VulkanUtil.h" - -// This shader references gl_FragDepth to prevent early fragment tests. -// They shouldn't happen since it uses discard, but Adreno detects that incorrectly - see #10634. -// This only affected the 5xx generation and was fixed sometime before driver version 512.384.0.0 (whatever that means). -// Strangely, this same code appears to fix a different issue on Exynos instead so now it's enabled on Mali as well. -static const char *stencil_fs_adreno = R"(#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable -#extension GL_ARB_conservative_depth : enable -layout (depth_unchanged) out float gl_FragDepth; -layout (binding = 0) uniform sampler2D tex; -layout (push_constant) uniform params { - int u_stencilValue; -}; -layout (location = 0) in vec2 v_texcoord0; -layout (location = 0) out vec4 fragColor0; - -void main() { - gl_FragDepth = gl_FragCoord.z; - - if (u_stencilValue == 0) { - fragColor0 = vec4(0.0); - } else { - vec4 index = texture(tex, v_texcoord0); - int indexBits = int(floor(index.a * 255.99)) & 0xFF; - if ((indexBits & u_stencilValue) == 0) - discard; - fragColor0 = index.aaaa; - } -} -)"; - -static const char *stencil_fs = R"(#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable -layout (binding = 0) uniform sampler2D tex; -layout (push_constant) uniform params { - int u_stencilValue; -}; -layout (location = 0) in vec2 v_texcoord0; -layout (location = 0) out vec4 fragColor0; - -void main() { - if (u_stencilValue == 0) { - fragColor0 = vec4(0.0); - } else { - vec4 index = texture(tex, v_texcoord0); - int indexBits = int(floor(index.a * 255.99)) & 0xFF; - if ((indexBits & u_stencilValue) == 0) - discard; - fragColor0 = index.aaaa; - } -} -)"; - - -static const char stencil_vs[] = R"(#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable -layout (location = 0) out vec2 v_texcoord0; -out gl_PerVertex { vec4 gl_Position; }; -void main() { - int id = gl_VertexIndex; - v_texcoord0.x = (id == 2) ? 2.0 : 0.0; - v_texcoord0.y = (id == 1) ? 2.0 : 0.0; - gl_Position = vec4(v_texcoord0 * vec2(2.0, 2.0) + vec2(-1.0, -1.0), 0.0, 1.0); -} -)"; - -// In Vulkan we should be able to simply copy the stencil data directly to a stencil buffer without -// messing about with bitplane textures and the like. Or actually, maybe not... Let's start with -// the traditional approach. -bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { - addr &= 0x3FFFFFFF; - if (!MayIntersectFramebuffer(addr)) { - return false; - } - - VirtualFramebuffer *dstBuffer = 0; - for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebuffer *vfb = vfbs_[i]; - if (vfb->fb_address == addr) { - dstBuffer = vfb; - } - } - if (!dstBuffer) { - return false; - } - - int values = 0; - u8 usedBits = 0; - - const u8 *src = Memory::GetPointer(addr); - if (!src) { - return false; - } - - switch (dstBuffer->format) { - case GE_FORMAT_565: - // Well, this doesn't make much sense. - return false; - case GE_FORMAT_5551: - usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 2; - break; - case GE_FORMAT_4444: - usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 16; - break; - case GE_FORMAT_8888: - usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 256; - break; - case GE_FORMAT_INVALID: - case GE_FORMAT_DEPTH16: - // Inconceivable. - _assert_(false); - break; - } - - std::string error; - if (!stencilVs_) { - VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); - - const char *stencil_fs_source = stencil_fs; - // See comment above the stencil_fs_adreno definition. - u32 vendorID = vulkan->GetPhysicalDeviceProperties().properties.vendorID; - if (g_Config.bVendorBugChecksEnabled && (draw_->GetBugs().Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL) || vendorID == VULKAN_VENDOR_ARM)) - stencil_fs_source = stencil_fs_adreno; - - stencilVs_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_VERTEX_BIT, stencil_vs, &error); - stencilFs_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, stencil_fs_source, &error); - } - VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS); - - VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - - shaderManager_->DirtyLastShader(); - textureCache_->ForgetLastTexture(); - - u16 w = dstBuffer->renderWidth; - u16 h = dstBuffer->renderHeight; - Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); - if (!tex) - return false; - - if (dstBuffer->fbo) { - // Typically, STENCIL_IS_ZERO means it's already bound, so this bind will be optimized away. - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::DONT_CARE }, "Stencil"); - } else { - // something is wrong... - } - - VkPipeline pipeline = vulkan2D_->GetPipeline(rp, stencilVs_, stencilFs_, false, Vulkan2D::VK2DDepthStencilMode::STENCIL_REPLACE_ALWAYS); - renderManager->BindPipeline(pipeline, PIPELINE_FLAG_USES_DEPTH_STENCIL); - renderManager->SetViewport({ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }); - renderManager->SetScissor(0, 0, (int)w, (int)h); - - draw_->BindTextures(0, 1, &tex); - VkImageView drawPixelsImageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); - VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(drawPixelsImageView, nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE); - - // Note: Even with skipZero, we don't necessarily start framebuffers at 0 in Vulkan. Clear anyway. - // Not an actual clear, because we need to draw to alpha only as well. - uint32_t value = 0; - renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, &value); - renderManager->SetStencilParams(0xFF, 0xFF, 0x00); - renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, VK_NULL_HANDLE, 0, 3); // full screen triangle - - for (int i = 1; i < values; i += i) { - if (!(usedBits & i)) { - // It's already zero, let's skip it. - continue; - } - - // These are the stencil bits that will be written. We discard when the bit doesn't match. - uint8_t writeMask = 0; - // This is the value to test the texture alpha against in the shader. - uint32_t value = 0; - if (dstBuffer->format == GE_FORMAT_4444) { - writeMask = i | (i << 4); - value = i * 16; - } else if (dstBuffer->format == GE_FORMAT_5551) { - writeMask = 0xFF; - value = i * 128; - } else { - writeMask = i; - value = i; - } - renderManager->SetStencilParams(writeMask, 0xFF, 0xFF); - // Need to specify both VERTEX and FRAGMENT bits here since that's what we set up in the pipeline layout, and we need - // that for the post shaders. There's probably not really a cost to this. - renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, &value); - renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, VK_NULL_HANDLE, 0, 3); // full screen triangle - } - - tex->Release(); - RebindFramebuffer("RebindFramebuffer - NotifyStencilUpload"); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - return true; -} diff --git a/android/jni/Android.mk b/android/jni/Android.mk index ae109b91d1..246278cf05 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -351,7 +351,6 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/GLES/DepalettizeShaderGLES.cpp \ $(SRC)/GPU/GLES/DepthBufferGLES.cpp \ $(SRC)/GPU/GLES/GPU_GLES.cpp.arm \ - $(SRC)/GPU/GLES/StencilBufferGLES.cpp \ $(SRC)/GPU/GLES/TextureCacheGLES.cpp.arm \ $(SRC)/GPU/GLES/DrawEngineGLES.cpp.arm \ $(SRC)/GPU/GLES/StateMappingGLES.cpp.arm \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 696987c6fd..dc7c0bc987 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -369,7 +369,6 @@ SOURCES_CXX += \ $(GPUDIR)/GLES/TextureCacheGLES.cpp \ $(GPUDIR)/GLES/ShaderManagerGLES.cpp \ $(GPUDIR)/GLES/StateMappingGLES.cpp \ - $(GPUDIR)/GLES/StencilBufferGLES.cpp \ $(EXTDIR)/glslang/OGLCompilersDLL/InitializeDll.cpp \ $(EXTDIR)/glslang/glslang/GenericCodeGen/CodeGen.cpp \ $(EXTDIR)/glslang/glslang/GenericCodeGen/Link.cpp \ @@ -732,7 +731,6 @@ SOURCES_CXX += \ $(GPUDIR)/Vulkan/PipelineManagerVulkan.cpp \ $(GPUDIR)/Vulkan/ShaderManagerVulkan.cpp \ $(GPUDIR)/Vulkan/StateMappingVulkan.cpp \ - $(GPUDIR)/Vulkan/StencilBufferVulkan.cpp \ $(GPUDIR)/Vulkan/TextureCacheVulkan.cpp \ $(GPUDIR)/Vulkan/VulkanUtil.cpp \ $(LIBRETRODIR)/LibretroVulkanContext.cpp \ @@ -747,7 +745,6 @@ SOURCES_CXX += \ $(GPUDIR)/Directx9/GPU_DX9.cpp \ $(GPUDIR)/Directx9/ShaderManagerDX9.cpp \ $(GPUDIR)/Directx9/StateMappingDX9.cpp \ - $(GPUDIR)/Directx9/StencilBufferDX9.cpp \ $(GPUDIR)/Directx9/TextureCacheDX9.cpp SOURCES_CXX += \ @@ -758,7 +755,6 @@ SOURCES_CXX += \ $(GPUDIR)/D3D11/D3D11Util.cpp \ $(GPUDIR)/D3D11/ShaderManagerD3D11.cpp \ $(GPUDIR)/D3D11/StateMappingD3D11.cpp \ - $(GPUDIR)/D3D11/StencilBufferD3D11.cpp \ $(GPUDIR)/D3D11/TextureCacheD3D11.cpp \ $(LIBRETRODIR)/LibretroD3D11Context.cpp From 787de814371e2dad36497269de5942bd3786c914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 24 Jul 2022 18:29:11 +0200 Subject: [PATCH 05/35] Switch to ShaderWriter. Works in OpenGL --- Common/GPU/ShaderWriter.cpp | 23 +++++++- GPU/Common/StencilCommon.cpp | 111 +++++++++++++++++++---------------- GPU/Common/StencilCommon.h | 6 ++ 3 files changed, 89 insertions(+), 51 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index d53f00169e..6d5c044e26 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -171,13 +171,23 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform break; } case GLSL_VULKAN: + { + int i = 0; + for (auto &input : inputs) { + F("layout(location = %d) in %s %s;\n", i, input.type, input.name); + i++; + } for (auto &varying : varyings) { F("layout(location = %d) %s out %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); } C("void main() {\n"); break; + } default: // OpenGL + for (auto &input : inputs) { + F("in %s %s;\n", input.type, input.name); + } for (auto &varying : varyings) { F("%s %s %s %s; // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic, varying.index); } @@ -224,12 +234,23 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var F("layout(location = %d) %s in %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); } C("layout(location = 0, index = 0) out vec4 fragColor0;\n"); + if (!uniforms.is_empty()) { + C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n"); + for (auto &uniform : uniforms) { + F("%s %s;\n", uniform.type, uniform.name); + } + C("};\n"); + } C("\nvoid main() {\n"); break; - default: + + default: // GLSL OpenGL for (auto &varying : varyings) { F("%s %s %s %s; // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); } + for (auto &uniform : uniforms) { + F("uniform %s %s;\n", uniform.type, uniform.name); + } if (!strcmp(lang_.fragColor0, "fragColor0")) { C("out vec4 fragColor0;\n"); } diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 94b7373952..e7fba95e79 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/GPU/Shader.h" +#include "Common/GPU/ShaderWriter.h" #include "Common/GPU/OpenGL/GLSLProgram.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -67,58 +68,58 @@ const UniformBufferDesc stencilUBDesc { sizeof(StencilUB), { { "stencilValue", 0, -1, UniformType::FLOAT1, 0 }, } }; -static const char *stencil_fs = R"( -#ifdef GL_ES -#ifdef GL_FRAGMENT_PRECISION_HIGH -precision highp float; -#else -precision mediump float; // just hope it's enough.. -#endif -#endif -#if __VERSION__ >= 130 -#define varying in -#define texture2D texture -#define gl_FragColor fragColor0 -out vec4 fragColor0; -#endif -varying vec2 v_texcoord0; -uniform float stencilValue; -uniform sampler2D tex; -float roundAndScaleTo255f(in float x) { return floor(x * 255.99); } -void main() { - vec4 index = texture2D(tex, v_texcoord0); - gl_FragColor = vec4(v_texcoord0.x, v_texcoord0.y, 0.0, index.a); - float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue); - // Bitwise operations on floats, ugh. - if (mod(floor(shifted), 2.0) < 0.99) discard; -} -)"; - -static const char *stencil_vs = R"( -#ifdef GL_ES -precision highp float; -#endif -#if __VERSION__ >= 130 -#define attribute in -#define varying out -#endif -attribute vec2 a_position; -varying vec2 v_texcoord0; -void main() { - v_texcoord0 = a_position * 2.0; // yes, this should be right. Should be 2.0 in the far corners. - gl_Position = vec4(v_texcoord0 * 2.0 - vec2(1.0, 1.0), 0.0, 1.0); -} -)"; - - -static const std::vector fsStencilSources = { - {ShaderLanguage::GLSL_1xx, stencil_fs} +// TODO: Merge this with UniformBufferDesc +static const UniformDef uniforms[1] = { + { "float", "stencilValue", 0 }, }; -static const std::vector vsStencilSources = { - {ShaderLanguage::GLSL_1xx, stencil_vs} +static const InputDef inputs[1] = { + { "vec2", "a_position" } }; +static const VaryingDef varyings[1] = { + { "vec2", "v_texcoord", "TEXCOORD0", 0, "highp" }, +}; + +void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { + ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); + writer.HighPrecisionFloat(); + + writer.DeclareSampler2D("samp", 0); + writer.DeclareTexture2D("tex", 0); + + if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { + writer.C("layout (depth_unchanged) out float gl_FragDepth;\n"); + } + + writer.C("float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n"); + + writer.BeginFSMain(uniforms, varyings); + + writer.C(" vec4 index = ").SampleTexture2D("tex", "samp", "v_texcoord.xy").C(";\n"); + writer.C(" vec4 outColor = vec4(v_texcoord.x, v_texcoord.y, 0.0, index.a);\n"); + writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n"); + // Bitwise operations on floats, ugh. + writer.C(" if (mod(floor(shifted), 2.0) < 0.99) discard;\n"); + + if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { + writer.C(" gl_FragDepth = gl_FragCoord.z;\n"); + } + + writer.EndFSMain("outColor"); +} + +void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) { + ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0); + + writer.BeginVSMain(inputs, Slice::empty(), varyings); + + writer.C(" v_texcoord = a_position * 2.0;\n"); // yes, this should be right. Should be 2.0 in the far corners. + writer.C(" gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);\n"); + + writer.EndVSMain(varyings); +} + bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { using namespace Draw; @@ -190,8 +191,15 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp textureCache_->ForgetLastTexture(); if (!stencilUploadPipeline_) { - stencilUploadFs_ = CreateShader(draw_, ShaderStage::Fragment, fsStencilSources); - stencilUploadVs_ = CreateShader(draw_, ShaderStage::Vertex, vsStencilSources); + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + + char *fsCode = new char[4000]; + char *vsCode = new char[4000]; + GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs()); + GenerateStencilVs(vsCode, shaderLanguageDesc); + + stencilUploadFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "stencil_fs"); + stencilUploadVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "stencil_vs"); _assert_(stencilUploadFs_ && stencilUploadVs_); @@ -223,6 +231,9 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp stencilUploadPipeline_ = draw_->CreateGraphicsPipeline(stencilWriteDesc); _assert_(stencilUploadPipeline_); + delete[] fsCode; + delete[] vsCode; + rasterNoCull->Release(); blendOff->Release(); stencilWrite->Release(); diff --git a/GPU/Common/StencilCommon.h b/GPU/Common/StencilCommon.h index 3a22336b5f..e9746012a6 100644 --- a/GPU/Common/StencilCommon.h +++ b/GPU/Common/StencilCommon.h @@ -1,3 +1,9 @@ #pragma once #include "Common/CommonTypes.h" + +#include "Common/GPU/thin3d.h" + +// Exposed for automated tests +void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs); +void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang); From 269bff9c0b1b8ed0ba5ae07cd64b34e49ac26755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 24 Jul 2022 18:43:27 +0200 Subject: [PATCH 06/35] Get D3D shaders to build (though not working correctly) --- Common/GPU/D3D9/thin3d_d3d9.cpp | 5 +++++ Common/GPU/ShaderWriter.cpp | 6 ++++++ Common/GPU/ShaderWriter.h | 1 + GPU/Common/StencilCommon.cpp | 4 ++-- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index d42833558a..9a48f297d2 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -23,6 +23,7 @@ #include "Common/Math/lin/matrix4x4.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/D3D9/D3D9StateCache.h" +#include "Common/StringUtils.h" #include "Common/Log.h" @@ -1062,6 +1063,10 @@ bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, si // No D3D9-compatible shader compiler installed. error = "D3D9 shader compiler not installed"; } + + ERROR_LOG(G3D, "Compile error: %s", error); + ERROR_LOG(G3D, "%s", LineNumberString(std::string((const char *)data)).c_str()); + OutputDebugStringA(source); OutputDebugStringA(error); if (errorBuffer) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 6d5c044e26..9c79bce1c2 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -162,6 +162,11 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform if (lang_.shaderLanguage == HLSL_D3D11) { C("uint gl_VertexIndex : SV_VertexID, "); } + // List the inputs. + for (auto &input : inputs) { + F("in %s %s : %s, ", input.type, input.name, input.semantic); + } + Rewind(2); // Get rid of the last comma. C(") {\n"); C(" vec4 gl_Position;\n"); @@ -305,6 +310,7 @@ void ShaderWriter::DeclareTexture2D(const char *name, int binding) { F("Texture2D %s : register(t%d);\n", name, binding); break; case HLSL_D3D9: + F("sampler %s: register(s%d);\n", name, binding); break; case GLSL_VULKAN: // In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1. diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index cb8d963be3..5e7f488723 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -19,6 +19,7 @@ struct InputDef { const char *type; const char *name; + const char *semantic; }; struct UniformDef { diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index e7fba95e79..e77dc663fa 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -74,7 +74,7 @@ static const UniformDef uniforms[1] = { }; static const InputDef inputs[1] = { - { "vec2", "a_position" } + { "vec2", "a_position", "POSITION", } }; static const VaryingDef varyings[1] = { @@ -100,7 +100,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.C(" vec4 outColor = vec4(v_texcoord.x, v_texcoord.y, 0.0, index.a);\n"); writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n"); // Bitwise operations on floats, ugh. - writer.C(" if (mod(floor(shifted), 2.0) < 0.99) discard;\n"); + writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n"); if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { writer.C(" gl_FragDepth = gl_FragCoord.z;\n"); From d26e637bb838e8c8c9b8af77db590a50df4b03f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 24 Jul 2022 20:07:29 +0200 Subject: [PATCH 07/35] Bufferless path for D3D11/Vulkan Though we still bind the buffer for simplicity.. --- Common/GPU/Shader.cpp | 2 ++ Common/GPU/Shader.h | 2 ++ Common/GPU/ShaderWriter.cpp | 7 ++++++- GPU/Common/ReinterpretFramebuffer.cpp | 5 +++-- GPU/Common/StencilCommon.cpp | 23 ++++++++++++++++------- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Common/GPU/Shader.cpp b/Common/GPU/Shader.cpp index eaca068ff5..5033e55ac1 100644 --- a/Common/GPU/Shader.cpp +++ b/Common/GPU/Shader.cpp @@ -86,12 +86,14 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) { texelFetch = "texelFetch"; forceMatrix4x4 = false; coefsFromBuffers = true; + vertexIndex = true; break; case HLSL_D3D9: case HLSL_D3D11: if (lang == HLSL_D3D11) { fragColor0 = "outfragment.target"; fragColor1 = "outfragment.target1"; + vertexIndex = true; // if declared as a semantic input } else { fragColor0 = "outfragment.target"; } diff --git a/Common/GPU/Shader.h b/Common/GPU/Shader.h index 71cd26cae6..bc8c0f4e81 100644 --- a/Common/GPU/Shader.h +++ b/Common/GPU/Shader.h @@ -52,6 +52,8 @@ struct ShaderLanguageDesc { const char *framebufferFetchExtension = nullptr; const char *vsOutPrefix = ""; const char *viewportYSign = ""; + + bool vertexIndex = false; bool glslES30 = false; // really glslES30Features. TODO: Clean this up. bool bitwiseOps = false; bool forceMatrix4x4 = false; diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 9c79bce1c2..c8c64d6a72 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -206,10 +206,15 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var switch (lang_.shaderLanguage) { case HLSL_D3D11: if (!uniforms.is_empty()) { + C("cbuffer base : register(b0) {\n"); + for (auto &uniform : uniforms) { - //F(" %s %s : %s;\n", uniform.type, uniform.name, uniform.index); + F(" %s %s;\n", uniform.type, uniform.name); } + + C("};\n"); } + // Let's do the varyings as parameters to main, no struct. C("vec4 main("); for (auto &varying : varyings) { diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index da2f0ef7b1..1f0f23b8c0 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -79,9 +79,10 @@ bool GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lan writer.C(" float x = -1.0 + float((gl_VertexIndex & 1) << 2);\n"); writer.C(" float y = -1.0 + float((gl_VertexIndex & 2) << 1);\n"); writer.C(" v_texcoord = (vec2(x, y) + vec2(1.0, 1.0)) * 0.5;\n"); - writer.F(" y *= %s1.0;\n", lang.viewportYSign); + if (strlen(lang.viewportYSign)) { + writer.F(" y *= %s1.0;\n", lang.viewportYSign); + } writer.C(" gl_Position = vec4(x, y, 0.0, 1.0);\n"); - writer.EndVSMain(varyings); return true; } diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index e77dc663fa..e556a42799 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -65,7 +65,7 @@ struct StencilUB { }; const UniformBufferDesc stencilUBDesc { sizeof(StencilUB), { - { "stencilValue", 0, -1, UniformType::FLOAT1, 0 }, + { "stencilValue", -1, 0, UniformType::FLOAT1, 0 }, } }; // TODO: Merge this with UniformBufferDesc @@ -97,7 +97,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.BeginFSMain(uniforms, varyings); writer.C(" vec4 index = ").SampleTexture2D("tex", "samp", "v_texcoord.xy").C(";\n"); - writer.C(" vec4 outColor = vec4(v_texcoord.x, v_texcoord.y, 0.0, index.a);\n"); + writer.C(" vec4 outColor = index.aaaa;\n"); // Only care about a. writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n"); // Bitwise operations on floats, ugh. writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n"); @@ -109,13 +109,21 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.EndFSMain("outColor"); } +// This can probably be shared with some other shaders, like reinterpret or the future depth upload. void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) { ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0); - writer.BeginVSMain(inputs, Slice::empty(), varyings); + writer.BeginVSMain(lang.vertexIndex ? Slice::empty() : inputs, Slice::empty(), varyings); - writer.C(" v_texcoord = a_position * 2.0;\n"); // yes, this should be right. Should be 2.0 in the far corners. + if (lang.vertexIndex) { + writer.C(" float x = float((gl_VertexIndex & 1) << 1);\n"); + writer.C(" float y = float(gl_VertexIndex & 2);\n"); + writer.C(" v_texcoord = vec2(x, y);\n"); + } else { + writer.C(" v_texcoord = a_position * 2.0;\n"); // yes, this should be right. Should be 2.0 in the far corners. + } writer.C(" gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);\n"); + writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign); writer.EndVSMain(varyings); } @@ -243,8 +251,8 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp stencilUploadSampler_ = draw_->CreateSamplerState(descNearest); } - // Fullscreen triangle - const float positions[6] = { + // Fullscreen triangle coordinates. + static const float positions[6] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, @@ -255,6 +263,7 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp // Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x. // Then after we're done, we'll just blit it across and stretch it there. Not worth doing // if already at 1x size though, of course. + // TODO: This path means that we don't write color alpha... Ugh. if (dstBuffer->width == dstBuffer->renderWidth || !dstBuffer->fbo) { useBlit = false; } @@ -292,7 +301,7 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp // It's already zero, let's skip it. continue; } - StencilUB ub; + StencilUB ub{}; if (dstBuffer->format == GE_FORMAT_4444) { draw_->SetStencilParams(0xFF, (i << 4) | i, 0xFF); ub.stencilValue = i * (16.0f / 255.0f); From 9963cd55f002bf393eafbe42e3d68641c3d8f1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 24 Jul 2022 20:08:04 +0200 Subject: [PATCH 08/35] Rebind the framebuffer only if we're in the blit path. --- GPU/Common/StencilCommon.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index e556a42799..8fa1fc0493 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -191,7 +191,7 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp // Clear destination alpha. // render_->Clear(0, 0, 0, GL_COLOR_BUFFER_BIT, 0x8, 0, 0, 0, 0); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE); return true; } @@ -320,10 +320,10 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp // Note that scissors don't affect blits on other APIs than OpenGL, so might want to try to get rid of this. draw_->SetScissorRect(0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight); draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST, "NotifyStencilUpload_Blit"); + RebindFramebuffer("RebindFramebuffer - Stencil"); } - + tex->Release(); - RebindFramebuffer("RebindFramebuffer - Stencil"); gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); return true; } From cacb2a32009352e45f8eba4ef7597c593fa23859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 24 Jul 2022 20:13:33 +0200 Subject: [PATCH 09/35] Unit test, comment --- unittest/TestShaderGenerators.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index ef4116cfaf..1c33bccca3 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -13,6 +13,7 @@ #include "GPU/Common/FragmentShaderGenerator.h" #include "GPU/Common/VertexShaderGenerator.h" #include "GPU/Common/ReinterpretFramebuffer.h" +#include "GPU/Common/StencilCommon.h" #if PPSSPP_PLATFORM(WINDOWS) #include "GPU/D3D11/D3D11Util.h" @@ -159,6 +160,8 @@ const char *ShaderLanguageToString(ShaderLanguage lang) { } bool TestReinterpretShaders() { + Draw::Bugs bugs; + ShaderLanguage languages[] = { #if PPSSPP_PLATFORM(WINDOWS) ShaderLanguage::HLSL_D3D11, @@ -197,6 +200,7 @@ bool TestReinterpretShaders() { printf("=== %s ===\n\n", ShaderLanguageToString(languages[k])); ShaderLanguageDesc desc(languages[k]); + std::string errorMessage; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -206,7 +210,6 @@ bool TestReinterpretShaders() { printf("Failed!\n%s\n", buffer); failed = true; } else { - std::string errorMessage; if (!TestCompileShader(buffer, languages[k], false, &errorMessage)) { printf("Error compiling fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; @@ -218,6 +221,23 @@ bool TestReinterpretShaders() { } } + GenerateStencilFs(buffer, desc, bugs); + if (!TestCompileShader(buffer, languages[k], false, &errorMessage)) { + printf("Error compiling stencil shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); + failed = true; + return false; + } else { + printf("===\n%s\n===\n", buffer); + } + + GenerateStencilVs(buffer, desc); + if (!TestCompileShader(buffer, languages[k], false, &errorMessage)) { + printf("Error compiling stencil shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); + failed = true; + return false; + } else { + printf("===\n%s\n===\n", buffer); + } } return !failed; } From 41e327a66bfca45a57df14e82a2de85e78cc42ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 2 Aug 2022 15:42:05 +0200 Subject: [PATCH 10/35] Cleanup and testfixes --- GPU/Common/DrawEngineCommon.h | 10 +++++ GPU/Common/FramebufferManagerCommon.cpp | 2 +- GPU/Common/FramebufferManagerCommon.h | 3 +- GPU/Common/StencilCommon.cpp | 20 ++++----- GPU/D3D11/FramebufferManagerD3D11.cpp | 2 +- GPU/GLES/DrawEngineGLES.h | 10 ----- GPU/GLES/FramebufferManagerGLES.h | 2 - GPU/GPUCommon.cpp | 2 +- UWP/GPU_UWP/GPU_UWP.vcxproj | 1 - UWP/GPU_UWP/GPU_UWP.vcxproj.filters | 1 - android/jni/Android.mk | 1 - unittest/TestShaderGenerators.cpp | 60 +++++++++++++++++++------ 12 files changed, 71 insertions(+), 43 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index e5b7f952da..65391be14f 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -35,6 +35,16 @@ enum { DECODED_INDEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * 16, }; +enum { + TEX_SLOT_PSP_TEXTURE = 0, + TEX_SLOT_SHADERBLEND_SRC = 1, + TEX_SLOT_ALPHATEST = 2, + TEX_SLOT_CLUT = 3, + TEX_SLOT_SPLINE_POINTS = 4, + TEX_SLOT_SPLINE_WEIGHTS_U = 5, + TEX_SLOT_SPLINE_WEIGHTS_V = 6, +}; + inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) { // 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. diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 6d7f0446ee..9478bf34fd 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -469,7 +469,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects) { gpu->PerformMemoryUpload(params.fb_address, byteSize); - NotifyStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO); + PerformStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO); // TODO: Is it worth trying to upload the depth buffer (only if it wasn't copied above..?) } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 18e99fd559..894d7266e8 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -19,7 +19,6 @@ // Here's a list of functionality to unify into FramebufferManagerCommon: // * DrawActiveTexture // * BlitFramebuffer -// * StencilBuffer*.cpp // // Also, in TextureCache we should be able to unify texture-based depal. @@ -253,7 +252,7 @@ public: void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt); void UpdateFromMemory(u32 addr, int size, bool safe); void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor); - bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR); + bool PerformStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR); // Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it. // In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless // read framebuffers is on, in which case this should always return false). diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 8fa1fc0493..fb0a6172a2 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -17,15 +17,13 @@ #include "Common/GPU/Shader.h" #include "Common/GPU/ShaderWriter.h" -#include "Common/GPU/OpenGL/GLSLProgram.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" -#include "GPU/GLES/DrawEngineGLES.h" -#include "GPU/GLES/FramebufferManagerGLES.h" -#include "GPU/GLES/ShaderManagerGLES.h" -#include "GPU/GLES/TextureCacheGLES.h" +#include "GPU/Common/DrawEngineCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" +#include "GPU/Common/TextureCacheCommon.h" static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { const u32 *ptr = (const u32 *)ptr8; @@ -128,7 +126,7 @@ void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) { writer.EndVSMain(varyings); } -bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { +bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilUpload flags) { using namespace Draw; addr &= 0x3FFFFFFF; @@ -179,9 +177,11 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp if (usedBits == 0) { if (flags == StencilUpload::STENCIL_IS_ZERO) { - // Common when creating buffers, it's already 0. We're done. + // Common when creating buffers, it's already 0. + // We're done. return false; } + shaderManager_->DirtyLastShader(); // Let's not bother with the shader if it's just zero. @@ -189,8 +189,8 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "NotifyStencilUpload_Clear"); } - // Clear destination alpha. - // render_->Clear(0, 0, 0, GL_COLOR_BUFFER_BIT, 0x8, 0, 0, 0, 0); + // Here we might want to clear destination alpha by using a draw, but we haven't found a need for this yet. + // Will implement when needed... gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE); return true; } @@ -324,6 +324,6 @@ bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUp } tex->Release(); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); return true; } diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 6900e115d6..6d58e5caac 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -207,7 +207,7 @@ void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float coord[i].pos.y = -(coord[i].pos.y * invDestH - 1.0f); } - if (g_display_rotation != DisplayRotation::ROTATE_0) { + if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display_rotation != DisplayRotation::ROTATE_0) { for (int i = 0; i < 4; i++) { // backwards notation, should fix that... coord[i].pos = coord[i].pos * g_display_rot_matrix; diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 5554fe21e8..c016771e64 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -40,16 +40,6 @@ struct TransformedVertex; struct DecVtxFormat; -enum { - TEX_SLOT_PSP_TEXTURE = 0, - TEX_SLOT_SHADERBLEND_SRC = 1, - TEX_SLOT_ALPHATEST = 2, - TEX_SLOT_CLUT = 3, - TEX_SLOT_SPLINE_POINTS = 4, - TEX_SLOT_SPLINE_WEIGHTS_U = 5, - TEX_SLOT_SPLINE_WEIGHTS_V = 6, -}; - class TessellationDataTransferGLES : public TessellationDataTransfer { private: GLRTexture *data_tex[3]{}; diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 8347f059a2..94b06155e0 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -50,8 +50,6 @@ public: void DeviceLost() override; void DeviceRestore(Draw::DrawContext *draw) override; - bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR); - bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; protected: diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 9fc627fc75..03ab2629e8 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2933,7 +2933,7 @@ void GPUCommon::NotifyVideoUpload(u32 addr, int size, int width, int format) { bool GPUCommon::PerformStencilUpload(u32 dest, int size) { if (framebufferManager_->MayIntersectFramebuffer(dest)) { - framebufferManager_->NotifyStencilUpload(dest, size); + framebufferManager_->PerformStencilUpload(dest, size); return true; } return false; diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj index 0d09bebc50..81ab4c82a0 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj @@ -470,7 +470,6 @@ - diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters index 84ab7ec547..f1f1de951b 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters @@ -30,7 +30,6 @@ - diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 246278cf05..b2e4e6fe37 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -133,7 +133,6 @@ VULKAN_FILES := \ $(SRC)/GPU/Vulkan/PipelineManagerVulkan.cpp \ $(SRC)/GPU/Vulkan/ShaderManagerVulkan.cpp \ $(SRC)/GPU/Vulkan/StateMappingVulkan.cpp \ - $(SRC)/GPU/Vulkan/StencilBufferVulkan.cpp \ $(SRC)/GPU/Vulkan/TextureCacheVulkan.cpp \ $(SRC)/GPU/Vulkan/DepalettizeShaderVulkan.cpp \ $(SRC)/GPU/Vulkan/VulkanUtil.cpp \ diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index 1c33bccca3..8583a18c60 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -90,18 +90,18 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs } } -bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex, std::string *errorMessage) { +bool TestCompileShader(const char *buffer, ShaderLanguage lang, ShaderStage stage, std::string *errorMessage) { std::vector spirv; switch (lang) { #if PPSSPP_PLATFORM(WINDOWS) case ShaderLanguage::HLSL_D3D11: { - auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), vertex ? "vs_4_0" : "ps_4_0", 0); + auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), stage == ShaderStage::Vertex ? "vs_4_0" : "ps_4_0", 0); return !output.empty(); } case ShaderLanguage::HLSL_D3D9: { - LPD3DBLOB blob = CompileShaderToByteCodeD3D9(buffer, vertex ? "vs_2_0" : "ps_2_0", errorMessage); + LPD3DBLOB blob = CompileShaderToByteCodeD3D9(buffer, stage == ShaderStage::Vertex ? "vs_2_0" : "ps_2_0", errorMessage); if (blob) { blob->Release(); return true; @@ -112,11 +112,11 @@ bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex, std #endif case ShaderLanguage::GLSL_VULKAN: - return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::VULKAN, spirv, errorMessage); + return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::VULKAN, spirv, errorMessage); case ShaderLanguage::GLSL_1xx: - return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GL140, spirv, errorMessage); + return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GL140, spirv, errorMessage); case ShaderLanguage::GLSL_3xx: - return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GLES300, spirv, errorMessage); + return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GLES300, spirv, errorMessage); default: return false; } @@ -186,7 +186,7 @@ bool TestReinterpretShaders() { failed = true; } else { std::string errorMessage; - if (!TestCompileShader(buffer, languages[k], true, &errorMessage)) { + if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) { printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; return false; @@ -210,7 +210,7 @@ bool TestReinterpretShaders() { printf("Failed!\n%s\n", buffer); failed = true; } else { - if (!TestCompileShader(buffer, languages[k], false, &errorMessage)) { + if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { printf("Error compiling fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; return false; @@ -220,9 +220,37 @@ bool TestReinterpretShaders() { } } } + } + delete[] buffer; + return !failed; +} + +bool TestStencilShaders() { + Draw::Bugs bugs; + + ShaderLanguage languages[] = { +#if PPSSPP_PLATFORM(WINDOWS) + ShaderLanguage::HLSL_D3D9, + ShaderLanguage::HLSL_D3D11, +#endif + ShaderLanguage::GLSL_VULKAN, + ShaderLanguage::GLSL_3xx, + }; + + char *buffer = new char[65536]; + + bool failed = false; + + for (int k = 0; k < ARRAY_SIZE(languages); k++) { + printf("=== %s ===\n\n", ShaderLanguageToString(languages[k])); + + ShaderLanguageDesc desc(languages[k]); + std::string errorMessage; + + // Generate all despite failures - it's only 6. GenerateStencilFs(buffer, desc, bugs); - if (!TestCompileShader(buffer, languages[k], false, &errorMessage)) { + if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { printf("Error compiling stencil shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; return false; @@ -231,7 +259,7 @@ bool TestReinterpretShaders() { } GenerateStencilVs(buffer, desc); - if (!TestCompileShader(buffer, languages[k], false, &errorMessage)) { + if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) { printf("Error compiling stencil shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; return false; @@ -239,6 +267,8 @@ bool TestReinterpretShaders() { printf("===\n%s\n===\n", buffer); } } + + delete[] buffer; return !failed; } @@ -301,7 +331,7 @@ bool TestVertexShaders() { for (int j = 0; j < numLanguages; j++) { if (generateSuccess[j]) { std::string errorMessage; - if (!TestCompileShader(buffer[j], languages[j], true, &errorMessage)) { + if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Vertex, &errorMessage)) { printf("Error compiling vertex shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer[j]).c_str(), errorMessage.c_str()); return false; } @@ -363,7 +393,7 @@ bool TestFragmentShaders() { for (int j = 0; j < numLanguages; j++) { if (generateSuccess[j]) { std::string errorMessage; - if (!TestCompileShader(buffer[j], languages[j], false, &errorMessage)) { + if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Fragment, &errorMessage)) { printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer[j]).c_str(), errorMessage.c_str()); return false; } @@ -389,7 +419,7 @@ bool TestShaderGenerators() { init_glslang(); #endif - if (!TestFragmentShaders()) { + if (!TestStencilShaders()) { return false; } @@ -397,6 +427,10 @@ bool TestShaderGenerators() { return false; } + if (!TestFragmentShaders()) { + return false; + } + if (!TestVertexShaders()) { return false; } From 3e1ccf1311062361ca4de772325b98f758e2f817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 13:40:21 +0200 Subject: [PATCH 11/35] Need a separate cap bit for stencil blits to prevent misuse on D3D9 --- Common/GPU/D3D11/thin3d_d3d11.cpp | 3 ++- Common/GPU/D3D9/thin3d_d3d9.cpp | 1 + Common/GPU/OpenGL/thin3d_gl.cpp | 1 + Common/GPU/Vulkan/thin3d_vulkan.cpp | 1 + Common/GPU/thin3d.h | 1 + GPU/Common/StencilCommon.cpp | 2 +- 6 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index d3a33d85fe..eeba9d24a3 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -285,8 +285,9 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.framebufferBlitSupported = false; caps_.framebufferCopySupported = true; caps_.framebufferDepthBlitSupported = false; + caps_.framebufferStencilBlitSupported = false; caps_.framebufferDepthCopySupported = true; - caps_.framebufferSeparateDepthCopySupported = false; + caps_.framebufferSeparateDepthCopySupported = false; // Though could be emulated with a draw. caps_.texture3DSupported = true; D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 9a48f297d2..2b0f1a0faa 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -664,6 +664,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.framebufferBlitSupported = true; caps_.framebufferCopySupported = false; caps_.framebufferDepthBlitSupported = true; + caps_.framebufferStencilBlitSupported = false; caps_.framebufferDepthCopySupported = false; caps_.framebufferSeparateDepthCopySupported = false; caps_.texture3DSupported = true; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 77e1d822cc..29c51cbeb5 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -538,6 +538,7 @@ OpenGLContext::OpenGLContext() { caps_.framebufferCopySupported = gl_extensions.OES_copy_image || gl_extensions.NV_copy_image || gl_extensions.EXT_copy_image || gl_extensions.ARB_copy_image; caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3; caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported; + caps_.framebufferStencilBlitSupported = caps_.framebufferBlitSupported; caps_.depthClampSupported = gl_extensions.ARB_depth_clamp; if (gl_extensions.IsGLES) { caps_.clipDistanceSupported = gl_extensions.EXT_clip_cull_distance || gl_extensions.APPLE_clip_distance; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 2e329f1d45..1a84cb5ecb 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -784,6 +784,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) caps_.framebufferBlitSupported = true; caps_.framebufferCopySupported = true; caps_.framebufferDepthBlitSupported = vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat; + caps_.framebufferStencilBlitSupported = caps_.framebufferDepthBlitSupported; caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case. caps_.framebufferSeparateDepthCopySupported = true; // Will pretty much always be the case. caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index c832d6cc2e..845914d344 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -533,6 +533,7 @@ struct DeviceCaps { bool framebufferDepthCopySupported; bool framebufferSeparateDepthCopySupported; bool framebufferDepthBlitSupported; + bool framebufferStencilBlitSupported; bool framebufferFetchSupported; bool texture3DSupported; diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index fb0a6172a2..ca661fa1f0 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -258,7 +258,7 @@ bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilU 0.0, 1.0, }; - bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported; + bool useBlit = draw_->GetDeviceCaps().framebufferStencilBlitSupported; // Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x. // Then after we're done, we'll just blit it across and stretch it there. Not worth doing From 59b3df0643ac18d5ddcb5602379e214ec9a86d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 11:42:37 +0200 Subject: [PATCH 12/35] Draw2D --- CMakeLists.txt | 2 + GPU/Common/Draw2D.cpp | 123 ++++++++++++++++++++++++ GPU/Common/Draw2D.h | 9 ++ GPU/Common/FramebufferManagerCommon.cpp | 4 + GPU/Common/FramebufferManagerCommon.h | 12 ++- GPU/GPU.vcxproj | 4 +- GPU/GPU.vcxproj.filters | 8 +- android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 9 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 GPU/Common/Draw2D.cpp create mode 100644 GPU/Common/Draw2D.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 670e5f437c..d4b2fdc242 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1529,6 +1529,8 @@ endif() set(GPU_SOURCES ${GPU_IMPLS} ${GPU_NEON} + GPU/Common/Draw2D.cpp + GPU/Common/Draw2D.h GPU/Common/DepalettizeShaderCommon.cpp GPU/Common/DepalettizeShaderCommon.h GPU/Common/FragmentShaderGenerator.cpp diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp new file mode 100644 index 0000000000..b827a3cf75 --- /dev/null +++ b/GPU/Common/Draw2D.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2014- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Common/GPU/Shader.h" +#include "Common/GPU/ShaderWriter.h" +#include "Common/GPU/thin3d.h" +#include "Core/Config.h" +#include "Core/ConfigValues.h" +#include "Core/Reporting.h" +#include "GPU/Common/Draw2D.h" +#include "GPU/Common/DrawEngineCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" +#include "GPU/Common/TextureCacheCommon.h" + +static const InputDef inputs[2] = { + { "vec2", "a_position", "POSITION" }, + { "vec2", "a_texcoord", "TEXCOORD0" }, +}; + +static const VaryingDef varyings[1] = { + { "vec2", "v_texcoord", "TEXCOORD0", 0, "highp" }, +}; + +void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { + ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); + writer.DeclareSampler2D("samp", 0); + writer.DeclareTexture2D("tex", 0); + writer.BeginFSMain(Slice::empty(), varyings); + writer.C(" vec4 outColor = ").SampleTexture2D("tex", "samp", "v_texcoord.xy").C(";\n"); + writer.EndFSMain("outColor"); +} + +void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) { + ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0); + + writer.BeginVSMain(inputs, Slice::empty(), varyings); + + writer.C(" v_texcoord = a_texcoord;\n"); // yes, this should be right. Should be 2.0 in the far corners. + writer.C(" gl_Position = a_position;\n"); + writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign); + + writer.EndVSMain(varyings); +} + +// verts have positions in clip coordinates. +void FramebufferManagerCommon::Draw2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, float viewportWidth, float viewportHeight) { + using namespace Draw; + + if (!draw2DPipelineLinear_) { + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + + char *fsCode = new char[4000]; + char *vsCode = new char[4000]; + GenerateDraw2DFs(fsCode, shaderLanguageDesc, draw_->GetBugs()); + GenerateDraw2DVS(vsCode, shaderLanguageDesc); + + draw2DFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "draw2d_fs"); + draw2DVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "draw2d_vs"); + + _assert_(stencilUploadFs_ && stencilUploadVs_); + + InputLayoutDesc desc = { + { + { 16, false }, + }, + { + { 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 }, + { 16, SEM_TEXCOORD0, DataFormat::R32G32_FLOAT, 8 }, + }, + }; + InputLayout *inputLayout = draw_->CreateInputLayout(desc); + + BlendState *blendOff = draw_->CreateBlendState({ false, 0xF }); + DepthStencilStateDesc dsDesc{}; + DepthStencilState *noDepthStencil = draw_->CreateDepthStencilState(dsDesc); + RasterState *rasterNoCull = draw_->CreateRasterState({}); + + PipelineDesc stencilWriteDesc{ + Primitive::TRIANGLE_STRIP, + { draw2DVs_, draw2DFs_ }, + inputLayout, noDepthStencil, blendOff, rasterNoCull, nullptr, + }; + draw2DPipelineLinear_ = draw_->CreateGraphicsPipeline(stencilWriteDesc); + _assert_(draw2DPipelineLinear_); + + delete[] fsCode; + delete[] vsCode; + + rasterNoCull->Release(); + blendOff->Release(); + noDepthStencil->Release(); + inputLayout->Release(); + + SamplerStateDesc descLinear{}; + descLinear.magFilter = TextureFilter::LINEAR; + descLinear.minFilter = TextureFilter::LINEAR; + descLinear.mipFilter = TextureFilter::LINEAR; + descLinear.wrapU = TextureAddressMode::CLAMP_TO_EDGE; + descLinear.wrapV = TextureAddressMode::CLAMP_TO_EDGE; + draw2DSamplerLinear_= draw_->CreateSamplerState(descLinear); + } + + draw_->BindPipeline(draw2DPipelineLinear_); + draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); + draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &draw2DSamplerLinear_); + draw_->DrawUP(verts, vertexCount); + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); +} diff --git a/GPU/Common/Draw2D.h b/GPU/Common/Draw2D.h new file mode 100644 index 0000000000..34c171e7a0 --- /dev/null +++ b/GPU/Common/Draw2D.h @@ -0,0 +1,9 @@ +#pragma once + +// For framebuffer copies and similar things that just require passthrough. +struct Draw2DVertex { + float x; + float y; + float u; + float v; +}; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 9478bf34fd..fec63dcb81 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2492,6 +2492,10 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(stencilUploadVs_); DoRelease(stencilUploadSampler_); DoRelease(stencilUploadPipeline_); + DoRelease(draw2DPipelineLinear_); + DoRelease(draw2DSamplerLinear_); + DoRelease(draw2DVs_); + DoRelease(draw2DFs_); presentation_->DeviceLost(); draw_ = nullptr; } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 894d7266e8..5ec21e88b0 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -29,11 +29,11 @@ #include "Common/CommonTypes.h" #include "Common/Log.h" -#include "Core/MemMap.h" +#include "Common/GPU/thin3d.h" #include "GPU/GPU.h" #include "GPU/ge_constants.h" #include "GPU/GPUInterface.h" -#include "Common/GPU/thin3d.h" +#include "GPU/Common/Draw2D.h" enum { FB_USAGE_DISPLAYED_FRAMEBUFFER = 1, @@ -357,6 +357,8 @@ protected: virtual void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) = 0; virtual void Bind2DShader() = 0; + void Draw2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, float viewportWidth, float viewportHeight); + bool UpdateSize(); void FlushBeforeCopy(); @@ -473,4 +475,10 @@ protected: Draw::ShaderModule *stencilUploadVs_ = nullptr; Draw::ShaderModule *stencilUploadFs_ = nullptr; Draw::SamplerState *stencilUploadSampler_ = nullptr; + + // Draw2D pipelines + Draw::Pipeline *draw2DPipelineLinear_ = nullptr; + Draw::SamplerState *draw2DSamplerLinear_ = nullptr; + Draw::ShaderModule *draw2DVs_ = nullptr; + Draw::ShaderModule *draw2DFs_ = nullptr; }; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index ae899f0cd2..ca6cd6a03d 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -338,6 +338,7 @@ + @@ -459,6 +460,7 @@ + @@ -666,4 +668,4 @@ - + \ No newline at end of file diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 9c8d6b0f93..db9157dde0 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -264,6 +264,9 @@ Software + + Common + @@ -518,6 +521,9 @@ Software + + Common + @@ -535,4 +541,4 @@ Shaders - + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index b2e4e6fe37..03dd60d89e 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -319,6 +319,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/GPUState.cpp \ $(SRC)/GPU/GeConstants.cpp \ $(SRC)/GPU/GeDisasm.cpp \ + $(SRC)/GPU/Common/Draw2D.cpp \ $(SRC)/GPU/Common/DepalettizeShaderCommon.cpp \ $(SRC)/GPU/Common/FragmentShaderGenerator.cpp \ $(SRC)/GPU/Common/FramebufferManagerCommon.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index dc7c0bc987..37e42af0ee 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -315,6 +315,7 @@ SOURCES_C +=\ $(COMMONDIR)/GPU/OpenGL/gl3stub.c SOURCES_CXX += \ + $(GPUCOMMONDIR)/Draw2D.cpp \ $(GPUCOMMONDIR)/VertexDecoderCommon.cpp \ $(GPUCOMMONDIR)/GPUStateUtils.cpp \ $(GPUCOMMONDIR)/DrawEngineCommon.cpp \ From d55c4a3456dd477b713bdf2789ab28b504425857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 12:09:24 +0200 Subject: [PATCH 13/35] Convert the D3D11 DrawActiveTexture to thin3d --- GPU/Common/Draw2D.cpp | 12 ++++--- GPU/Common/FramebufferManagerCommon.h | 2 +- GPU/D3D11/FramebufferManagerD3D11.cpp | 49 ++++++++++----------------- 3 files changed, 26 insertions(+), 37 deletions(-) diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index b827a3cf75..bec9e166e4 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -50,14 +50,14 @@ void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) { writer.BeginVSMain(inputs, Slice::empty(), varyings); writer.C(" v_texcoord = a_texcoord;\n"); // yes, this should be right. Should be 2.0 in the far corners. - writer.C(" gl_Position = a_position;\n"); + writer.C(" gl_Position = vec4(a_position, 0.0, 1.0);\n"); writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign); writer.EndVSMain(varyings); } // verts have positions in clip coordinates. -void FramebufferManagerCommon::Draw2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, float viewportWidth, float viewportHeight) { +void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount) { using namespace Draw; if (!draw2DPipelineLinear_) { @@ -71,7 +71,7 @@ void FramebufferManagerCommon::Draw2D(Draw::Texture *tex, Draw2DVertex *verts, i draw2DFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "draw2d_fs"); draw2DVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "draw2d_vs"); - _assert_(stencilUploadFs_ && stencilUploadVs_); + _assert_(draw2DFs_ && draw2DVs_); InputLayoutDesc desc = { { @@ -79,7 +79,7 @@ void FramebufferManagerCommon::Draw2D(Draw::Texture *tex, Draw2DVertex *verts, i }, { { 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 }, - { 16, SEM_TEXCOORD0, DataFormat::R32G32_FLOAT, 8 }, + { 0, SEM_TEXCOORD0, DataFormat::R32G32_FLOAT, 8 }, }, }; InputLayout *inputLayout = draw_->CreateInputLayout(desc); @@ -115,7 +115,9 @@ void FramebufferManagerCommon::Draw2D(Draw::Texture *tex, Draw2DVertex *verts, i } draw_->BindPipeline(draw2DPipelineLinear_); - draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); + if (tex) { + draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); + } draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &draw2DSamplerLinear_); draw_->DrawUP(verts, vertexCount); diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 5ec21e88b0..14a1fa142b 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -357,7 +357,7 @@ protected: virtual void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) = 0; virtual void Bind2DShader() = 0; - void Draw2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, float viewportWidth, float viewportHeight); + void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount); bool UpdateSize(); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 6d58e5caac..2162c1ae1e 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -171,14 +171,12 @@ void FramebufferManagerD3D11::SetDrawEngine(DrawEngineD3D11 *td) { } void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) { - struct Coord { - Lin::Vec3 pos; float u, v; - }; - Coord coord[4] = { - {{x, y, 0}, u0, v0}, - {{x + w, y, 0}, u1, v0}, - {{x + w, y + h,0}, u1, v1}, - {{x, y + h, 0}, u0, v1}, + // Will be drawn as a strip. + Draw2DVertex coord[4] = { + {x, y, u0, v0}, + {x + w, y, u1, v0}, + {x + w, y + h, u1, v1}, + {x, y + h, u0, v1}, }; if (uvRotation != ROTATION_LOCKED_HORIZONTAL) { @@ -200,39 +198,28 @@ void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float } } - float invDestW = 1.0f / (destW * 0.5f); - float invDestH = 1.0f / (destH * 0.5f); + const float invDestW = 2.0f / destW; + const float invDestH = 2.0f / destH; for (int i = 0; i < 4; i++) { - coord[i].pos.x = coord[i].pos.x * invDestW - 1.0f; - coord[i].pos.y = -(coord[i].pos.y * invDestH - 1.0f); + coord[i].x = coord[i].x * invDestW - 1.0f; + coord[i].y = coord[i].y * invDestH - 1.0f; } if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display_rotation != DisplayRotation::ROTATE_0) { for (int i = 0; i < 4; i++) { // backwards notation, should fix that... - coord[i].pos = coord[i].pos * g_display_rot_matrix; + Lin::Vec3 pos = Lin::Vec3(coord[i].x, coord[i].y, 0.0); + pos = pos * g_display_rot_matrix; + coord[i].x = pos.x; + coord[i].y = pos.y; } } - // The above code is for FAN geometry but we can only do STRIP. So rearrange it a little. - D3D11_MAPPED_SUBRESOURCE map; - context_->Map(quadBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - float *dest = (float *)map.pData; - memcpy(dest, coord, sizeof(Coord)); - memcpy(dest + 5, coord + 1, sizeof(Coord)); - memcpy(dest + 10, coord + 3, sizeof(Coord)); - memcpy(dest + 15, coord + 2, sizeof(Coord)); - context_->Unmap(quadBuffer_, 0); + // Rearrange to strip form. + std::swap(coord[2], coord[3]); + + DrawStrip2D(nullptr, coord, 4); - context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); - context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0); - context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context_->PSSetSamplers(0, 1, (flags & DRAWTEX_LINEAR) ? &stockD3D11.samplerLinear2DClamp : &stockD3D11.samplerPoint2DClamp); - UINT stride = 20; - UINT offset = 0; - context_->IASetVertexBuffers(0, 1, &quadBuffer_, &stride, &offset); - context_->Draw(4, 0); gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); } From 1d3075566f01593f12e7ca9f5fb2dd5006a6d8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 12:14:28 +0200 Subject: [PATCH 14/35] Move to common (todo: merge with above) --- GPU/Common/Draw2D.cpp | 2 - GPU/Common/FramebufferManagerCommon.cpp | 59 ++++++++++++++++++++++++- GPU/Common/FramebufferManagerCommon.h | 2 +- GPU/D3D11/FramebufferManagerD3D11.cpp | 56 ----------------------- GPU/D3D11/FramebufferManagerD3D11.h | 1 - 5 files changed, 58 insertions(+), 62 deletions(-) diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index bec9e166e4..7d22dd817f 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -120,6 +120,4 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver } draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &draw2DSamplerLinear_); draw_->DrawUP(verts, vertexCount); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index fec63dcb81..1bdf8c0265 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -23,6 +23,9 @@ #include "Common/GPU/OpenGL/GLFeatures.h" #include "Common/Data/Convert/ColorConv.h" #include "Common/Data/Text/I18n.h" +#include "Common/Math/lin/matrix4x4.h" +#include "Common/Math/math_util.h" +#include "Common/System/Display.h" #include "Common/CommonTypes.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -44,8 +47,7 @@ #include "GPU/GPUState.h" FramebufferManagerCommon::FramebufferManagerCommon(Draw::DrawContext *draw) - : draw_(draw), - displayFormat_(GE_FORMAT_565) { + : draw_(draw), displayFormat_(GE_FORMAT_565) { presentation_ = new PresentationCommon(draw); } @@ -2504,3 +2506,56 @@ void FramebufferManagerCommon::DeviceRestore(Draw::DrawContext *draw) { draw_ = draw; presentation_->DeviceRestore(draw); } + +void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) { + // Will be drawn as a strip. + Draw2DVertex coord[4] = { + {x, y, u0, v0}, + {x + w, y, u1, v0}, + {x + w, y + h, u1, v1}, + {x, y + h, u0, v1}, + }; + + if (uvRotation != ROTATION_LOCKED_HORIZONTAL) { + float temp[8]; + int rotation = 0; + switch (uvRotation) { + case ROTATION_LOCKED_HORIZONTAL180: rotation = 2; break; + case ROTATION_LOCKED_VERTICAL: rotation = 1; break; + case ROTATION_LOCKED_VERTICAL180: rotation = 3; break; + } + for (int i = 0; i < 4; i++) { + temp[i * 2] = coord[((i + rotation) & 3)].u; + temp[i * 2 + 1] = coord[((i + rotation) & 3)].v; + } + + for (int i = 0; i < 4; i++) { + coord[i].u = temp[i * 2]; + coord[i].v = temp[i * 2 + 1]; + } + } + + const float invDestW = 2.0f / destW; + const float invDestH = 2.0f / destH; + for (int i = 0; i < 4; i++) { + coord[i].x = coord[i].x * invDestW - 1.0f; + coord[i].y = coord[i].y * invDestH - 1.0f; + } + + if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display_rotation != DisplayRotation::ROTATE_0) { + for (int i = 0; i < 4; i++) { + // backwards notation, should fix that... + Lin::Vec3 pos = Lin::Vec3(coord[i].x, coord[i].y, 0.0); + pos = pos * g_display_rot_matrix; + coord[i].x = pos.x; + coord[i].y = pos.y; + } + } + + // Rearrange to strip form. + std::swap(coord[2], coord[3]); + + DrawStrip2D(nullptr, coord, 4); + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); +} diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 14a1fa142b..9140ed18e9 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -354,7 +354,7 @@ protected: virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h); void SetViewport2D(int x, int y, int w, int h); Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height); - virtual void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) = 0; + virtual void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags); virtual void Bind2DShader() = 0; void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 2162c1ae1e..b4b406d774 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -21,9 +21,6 @@ #include "Common/Common.h" #include "Common/Data/Convert/ColorConv.h" -#include "Common/System/Display.h" -#include "Common/Math/lin/matrix4x4.h" -#include "Common/Math/math_util.h" #include "Common/GPU/thin3d.h" #include "Core/MemMap.h" @@ -170,59 +167,6 @@ void FramebufferManagerD3D11::SetDrawEngine(DrawEngineD3D11 *td) { drawEngine_ = td; } -void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) { - // Will be drawn as a strip. - Draw2DVertex coord[4] = { - {x, y, u0, v0}, - {x + w, y, u1, v0}, - {x + w, y + h, u1, v1}, - {x, y + h, u0, v1}, - }; - - if (uvRotation != ROTATION_LOCKED_HORIZONTAL) { - float temp[8]; - int rotation = 0; - switch (uvRotation) { - case ROTATION_LOCKED_HORIZONTAL180: rotation = 2; break; - case ROTATION_LOCKED_VERTICAL: rotation = 1; break; - case ROTATION_LOCKED_VERTICAL180: rotation = 3; break; - } - for (int i = 0; i < 4; i++) { - temp[i * 2] = coord[((i + rotation) & 3)].u; - temp[i * 2 + 1] = coord[((i + rotation) & 3)].v; - } - - for (int i = 0; i < 4; i++) { - coord[i].u = temp[i * 2]; - coord[i].v = temp[i * 2 + 1]; - } - } - - const float invDestW = 2.0f / destW; - const float invDestH = 2.0f / destH; - for (int i = 0; i < 4; i++) { - coord[i].x = coord[i].x * invDestW - 1.0f; - coord[i].y = coord[i].y * invDestH - 1.0f; - } - - if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display_rotation != DisplayRotation::ROTATE_0) { - for (int i = 0; i < 4; i++) { - // backwards notation, should fix that... - Lin::Vec3 pos = Lin::Vec3(coord[i].x, coord[i].y, 0.0); - pos = pos * g_display_rot_matrix; - coord[i].x = pos.x; - coord[i].y = pos.y; - } - } - - // Rearrange to strip form. - std::swap(coord[2], coord[3]); - - DrawStrip2D(nullptr, coord, 4); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); -} - void FramebufferManagerD3D11::Bind2DShader() { context_->IASetInputLayout(quadInputLayout_); context_->PSSetShader(quadPixelShader_, 0, 0); diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index db843c1a02..38d0d6623b 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -39,7 +39,6 @@ public: void SetTextureCache(TextureCacheD3D11 *tc); void SetShaderManager(ShaderManagerD3D11 *sm); void SetDrawEngine(DrawEngineD3D11 *td); - void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override; void EndFrame(); From 1fe2bced54e07d4b5c871984aad2a42f145a0aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 12:16:27 +0200 Subject: [PATCH 15/35] Delete the D3D9 impl of DrawActiveTexture --- GPU/Directx9/FramebufferManagerDX9.cpp | 60 -------------------------- GPU/Directx9/FramebufferManagerDX9.h | 1 - 2 files changed, 61 deletions(-) diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index 47e86fc0a0..681cd3accb 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -152,66 +152,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { drawEngine_ = td; } - void FramebufferManagerDX9::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) { - // TODO: StretchRect instead when possible? - float coord[20] = { - x,y,0, u0,v0, - x+w,y,0, u1,v0, - x+w,y+h,0, u1,v1, - x,y+h,0, u0,v1, - }; - - if (uvRotation != ROTATION_LOCKED_HORIZONTAL) { - float temp[8]; - int rotation = 0; - switch (uvRotation) { - case ROTATION_LOCKED_HORIZONTAL180: rotation = 2; break; - case ROTATION_LOCKED_VERTICAL: rotation = 1; break; - case ROTATION_LOCKED_VERTICAL180: rotation = 3; break; - } - - for (int i = 0; i < 4; i++) { - temp[i * 2] = coord[((i + rotation) & 3) * 5 + 3]; - temp[i * 2 + 1] = coord[((i + rotation) & 3) * 5 + 4]; - } - - for (int i = 0; i < 4; i++) { - coord[i * 5 + 3] = temp[i * 2]; - coord[i * 5 + 4] = temp[i * 2 + 1]; - } - } - - float invDestW = 1.0f / (destW * 0.5f); - float invDestH = 1.0f / (destH * 0.5f); - float halfPixelX = invDestW * 0.5f; - float halfPixelY = invDestH * 0.5f; - for (int i = 0; i < 4; i++) { - coord[i * 5] = coord[i * 5] * invDestW - 1.0f - halfPixelX; - coord[i * 5 + 1] = -(coord[i * 5 + 1] * invDestH - 1.0f - halfPixelY); - } - - if (flags & DRAWTEX_LINEAR) { - dxstate.texMagFilter.set(D3DTEXF_LINEAR); - dxstate.texMinFilter.set(D3DTEXF_LINEAR); - } else { - dxstate.texMagFilter.set(D3DTEXF_POINT); - dxstate.texMinFilter.set(D3DTEXF_POINT); - } - dxstate.texMipLodBias.set(0.0f); - dxstate.texMaxMipLevel.set(0); - dxstate.blend.disable(); - dxstate.cullMode.set(D3DCULL_NONE); - dxstate.depthTest.disable(); - dxstate.scissorTest.disable(); - dxstate.stencilTest.disable(); - dxstate.colorMask.set(0xF); - dxstate.stencilWriteMask.set(0xFF); - HRESULT hr = device_->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coord, 5 * sizeof(float)); - if (FAILED(hr)) { - ERROR_LOG_REPORT(G3D, "DrawActiveTexture() failed: %08x", (uint32_t)hr); - } - } - void FramebufferManagerDX9::Bind2DShader() { device_->SetVertexDeclaration(pFramebufferVertexDecl); device_->SetPixelShader(pFramebufferPixelShader); diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index c8dbbe249a..2cc4371c92 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -42,7 +42,6 @@ public: void SetTextureCache(TextureCacheDX9 *tc); void SetShaderManager(ShaderManagerDX9 *sm); void SetDrawEngine(DrawEngineDX9 *td); - void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override; void DestroyAllFBOs() override; From 6ca47076e70575fd41ae1b80a75da08148cfb53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 12:32:42 +0200 Subject: [PATCH 16/35] Delete the Vulkan implementation of DrawActiveTexture, fixups to shader gen --- Common/GPU/ShaderWriter.cpp | 44 ++++++++++-------- Common/GPU/ShaderWriter.h | 4 +- GPU/Common/Draw2D.cpp | 6 +-- GPU/Common/ReinterpretFramebuffer.cpp | 3 +- GPU/Common/StencilCommon.cpp | 4 +- GPU/Vulkan/FramebufferManagerVulkan.cpp | 60 ------------------------- GPU/Vulkan/FramebufferManagerVulkan.h | 3 -- 7 files changed, 35 insertions(+), 89 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index c8c64d6a72..3fee6a6fd3 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -6,7 +6,7 @@ #include "Common/GPU/ShaderWriter.h" #include "Common/Log.h" -const char *vulkan_glsl_preamble_fs = +const char * const vulkan_glsl_preamble_fs = "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" @@ -18,7 +18,7 @@ const char *vulkan_glsl_preamble_fs = "precision highp int;\n" "\n"; -const char *hlsl_preamble_fs = +const char * const hlsl_preamble_fs = "#define vec2 float2\n" "#define vec3 float3\n" "#define vec4 float4\n" @@ -35,14 +35,14 @@ const char *hlsl_preamble_fs = "#define highp\n" "#define mod(x, y) fmod(x, y)\n"; -const char *hlsl_d3d11_preamble_fs = +static const char * const hlsl_d3d11_preamble_fs = "#define DISCARD discard\n" "#define DISCARD_BELOW(x) clip(x);\n"; -const char *hlsl_d3d9_preamble_fs = +static const char * const hlsl_d3d9_preamble_fs = "#define DISCARD clip(-1)\n" "#define DISCARD_BELOW(x) clip(x)\n"; -const char *vulkan_glsl_preamble_vs = +static const char * const vulkan_glsl_preamble_vs = "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" @@ -51,7 +51,7 @@ const char *vulkan_glsl_preamble_vs = "precision highp float;\n" "\n"; -const char *hlsl_preamble_vs = +static const char * const hlsl_preamble_vs = "#define vec2 float2\n" "#define vec3 float3\n" "#define vec4 float4\n" @@ -66,6 +66,16 @@ const char *hlsl_preamble_vs = "#define highp\n" "\n"; +static const char * const semanticNames[8] = { + "POSITION", + "COLOR0", + "TEXCOORD0", + "TEXCOORD1", + "NORMAL", + "TANGENT", + "BINORMAL", +}; + // Unsafe. But doesn't matter, we'll use big buffers for shader gen. ShaderWriter & ShaderWriter::F(const char *format, ...) { va_list args; @@ -153,7 +163,7 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform { C("struct VS_OUTPUT {\n"); for (auto &varying : varyings) { - F(" %s %s : %s;\n", varying.type, varying.name, varying.semantic); + F(" %s %s : %s;\n", varying.type, varying.name, semanticNames[varying.semantic]); } F(" vec4 pos : %s;\n", lang_.shaderLanguage == HLSL_D3D11 ? "SV_Position" : "POSITION"); C("};\n"); @@ -164,27 +174,25 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform } // List the inputs. for (auto &input : inputs) { - F("in %s %s : %s, ", input.type, input.name, input.semantic); + F("in %s %s : %s, ", input.type, input.name, semanticNames[input.semantic]); } Rewind(2); // Get rid of the last comma. C(") {\n"); C(" vec4 gl_Position;\n"); for (auto &varying : varyings) { - F(" %s %s;\n", varying.type, varying.name); + F(" %s %s; // %s\n", varying.type, varying.name, semanticNames[varying.semantic]); } break; } case GLSL_VULKAN: { - int i = 0; for (auto &input : inputs) { - F("layout(location = %d) in %s %s;\n", i, input.type, input.name); - i++; + F("layout(location = %d) in %s %s;\n", input.semantic /*index*/, input.type, input.name); } for (auto &varying : varyings) { F("layout(location = %d) %s out %s %s; // %s\n", - varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); + varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]); } C("void main() {\n"); break; @@ -194,7 +202,7 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform F("in %s %s;\n", input.type, input.name); } for (auto &varying : varyings) { - F("%s %s %s %s; // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic, varying.index); + F("%s %s %s %s; // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic], varying.index); } C("void main() {\n"); break; @@ -218,7 +226,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var // Let's do the varyings as parameters to main, no struct. C("vec4 main("); for (auto &varying : varyings) { - F(" %s %s : %s, ", varying.type, varying.name, varying.semantic); + F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]); } // Erase the last comma Rewind(2); @@ -232,7 +240,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var // Let's do the varyings as parameters to main, no struct. C("vec4 main("); for (auto &varying : varyings) { - F(" %s %s : %s, ", varying.type, varying.name, varying.semantic); + F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]); } // Erase the last comma Rewind(2); @@ -241,7 +249,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var break; case GLSL_VULKAN: for (auto &varying : varyings) { - F("layout(location = %d) %s in %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); + F("layout(location = %d) %s in %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]); } C("layout(location = 0, index = 0) out vec4 fragColor0;\n"); if (!uniforms.is_empty()) { @@ -256,7 +264,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var default: // GLSL OpenGL for (auto &varying : varyings) { - F("%s %s %s %s; // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); + F("%s %s %s %s; // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]); } for (auto &uniform : uniforms) { F("uniform %s %s;\n", uniform.type, uniform.name); diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 5e7f488723..b4a4beb3cc 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -19,7 +19,7 @@ struct InputDef { const char *type; const char *name; - const char *semantic; + int semantic; }; struct UniformDef { @@ -31,7 +31,7 @@ struct UniformDef { struct VaryingDef { const char *type; const char *name; - const char *semantic; + int semantic; int index; const char *precision; }; diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 7d22dd817f..3f9ac35df4 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -27,12 +27,12 @@ #include "GPU/Common/TextureCacheCommon.h" static const InputDef inputs[2] = { - { "vec2", "a_position", "POSITION" }, - { "vec2", "a_texcoord", "TEXCOORD0" }, + { "vec2", "a_position", Draw::SEM_POSITION }, + { "vec2", "a_texcoord", Draw::SEM_TEXCOORD0 }, }; static const VaryingDef varyings[1] = { - { "vec2", "v_texcoord", "TEXCOORD0", 0, "highp" }, + { "vec2", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" }, }; void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index 1f0f23b8c0..aa1cd89a1b 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -3,10 +3,11 @@ #include "Common/GPU/Shader.h" #include "Common/GPU/ShaderWriter.h" #include "Common/Log.h" +#include "Common/GPU/thin3d.h" #include "GPU/Common/ReinterpretFramebuffer.h" static const VaryingDef varyings[1] = { - { "vec2", "v_texcoord", "TEXCOORD0", 0, "highp" }, + { "vec2", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" }, }; // TODO: We could possibly have an option to preserve any extra color precision? But gonna start without it. diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index ca661fa1f0..617880eb58 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -72,11 +72,11 @@ static const UniformDef uniforms[1] = { }; static const InputDef inputs[1] = { - { "vec2", "a_position", "POSITION", } + { "vec2", "a_position", Draw::SEM_POSITION, } }; static const VaryingDef varyings[1] = { - { "vec2", "v_texcoord", "TEXCOORD0", 0, "highp" }, + { "vec2", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" }, }; void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { diff --git a/GPU/Vulkan/FramebufferManagerVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp index 707c20da6e..b0dd6e956d 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.cpp +++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp @@ -170,66 +170,6 @@ void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, boo } } -void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) { - float texCoords[8] = { - u0,v0, - u1,v0, - u1,v1, - u0,v1, - }; - - if (uvRotation != ROTATION_LOCKED_HORIZONTAL) { - float temp[8]; - int rotation = 0; - switch (uvRotation) { - case ROTATION_LOCKED_HORIZONTAL180: rotation = 4; break; - case ROTATION_LOCKED_VERTICAL: rotation = 2; break; - case ROTATION_LOCKED_VERTICAL180: rotation = 6; break; - } - for (int i = 0; i < 8; i++) { - temp[i] = texCoords[(i + rotation) & 7]; - } - memcpy(texCoords, temp, sizeof(temp)); - } - - Vulkan2D::Vertex vtx[4] = { - {x, y, 0, texCoords[0], texCoords[1]}, - {x + w, y, 0, texCoords[2], texCoords[3]}, - {x, y + h, 0, texCoords[6], texCoords[7]}, - {x + w, y + h, 0, texCoords[4], texCoords[5]}, - }; - - float invDestW = 1.0f / (destW * 0.5f); - float invDestH = 1.0f / (destH * 0.5f); - for (int i = 0; i < 4; i++) { - vtx[i].x = vtx[i].x * invDestW - 1.0f; - vtx[i].y = vtx[i].y * invDestH - 1.0f; - } - - if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display_rotation != DisplayRotation::ROTATE_0) { - for (int i = 0; i < 4; i++) { - Lin::Vec3 v(vtx[i].x, vtx[i].y, 0.0f); - // backwards notation, should fix that... - v = v * g_display_rot_matrix; - vtx[i].x = v.x; - vtx[i].y = v.y; - } - } - - draw_->FlushState(); - - // TODO: Should probably use draw_ directly and not go low level - - VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - - VkImageView view = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); - VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE); - VkBuffer vbuffer; - VkDeviceSize offset = push_->Push(vtx, sizeof(vtx), &vbuffer); - renderManager->BindPipeline(cur2DPipeline_, (PipelineFlags)0); - renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4); -} - void FramebufferManagerVulkan::Bind2DShader() { VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS); cur2DPipeline_ = vulkan2D_->GetPipeline(rp, vsBasicTex_, fsBasicTex_); diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h index 45a07ef9ed..6f60b12652 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -43,9 +43,6 @@ public: void SetVulkan2D(Vulkan2D *vk2d) { vulkan2D_ = vk2d; } void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } - // x,y,w,h are relative to destW, destH which fill out the target completely. - void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override; - void BeginFrameVulkan(); // there's a BeginFrame in the base class, which this calls void EndFrame(); From 192e331b1195ea3bcd7ec1a3c4a41ee60d022c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 12:35:40 +0200 Subject: [PATCH 17/35] Delete the OpenGL implementation of DrawActiveTexture. --- GPU/GLES/FramebufferManagerGLES.cpp | 77 ----------------------------- GPU/GLES/FramebufferManagerGLES.h | 3 -- 2 files changed, 80 deletions(-) diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 42245c4d2e..0e8077e60f 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -162,83 +162,6 @@ FramebufferManagerGLES::~FramebufferManagerGLES() { delete [] convBuf_; } -// x, y, w, h are relative coordinates against destW/destH, which is not very intuitive. -// TODO: This could totally use fbo_blit in many cases. -void FramebufferManagerGLES::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) { - float texCoords[8] = { - u0,v0, - u1,v0, - u1,v1, - u0,v1, - }; - - if (uvRotation != ROTATION_LOCKED_HORIZONTAL) { - float temp[8]; - int rotation = 0; - // Vertical and Vertical180 needed swapping after we changed the coordinate system. - switch (uvRotation) { - case ROTATION_LOCKED_HORIZONTAL180: rotation = 4; break; - case ROTATION_LOCKED_VERTICAL: rotation = 6; break; - case ROTATION_LOCKED_VERTICAL180: rotation = 2; break; - } - for (int i = 0; i < 8; i++) { - temp[i] = texCoords[(i + rotation) & 7]; - } - memcpy(texCoords, temp, sizeof(temp)); - } - - float pos[12] = { - x,y,0, - x + w,y,0, - x + w,y + h,0, - x,y + h,0 - }; - - float invDestW = 1.0f / (destW * 0.5f); - float invDestH = 1.0f / (destH * 0.5f); - for (int i = 0; i < 4; i++) { - pos[i * 3] = pos[i * 3] * invDestW - 1.0f; - pos[i * 3 + 1] = pos[i * 3 + 1] * invDestH - 1.0f; - } - - // We always want a plain state here, well, except for when it's used by the stencil stuff... - render_->SetDepth(false, false, GL_ALWAYS); - render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE, GL_FALSE); - if (!(flags & DRAWTEX_KEEP_STENCIL_ALPHA)) { - render_->SetNoBlendAndMask(0xF); - render_->SetStencilDisabled(); - } - - // Upscaling postshaders don't look well with linear - if (flags & DRAWTEX_LINEAR) { - render_->SetTextureSampler(0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_LINEAR, GL_LINEAR, 0.0f); - } else { - render_->SetTextureSampler(0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_NEAREST, GL_NEAREST, 0.0f); - } - - Simple2DVertex verts[4]; - memcpy(verts[0].pos, &pos[0], 12); - memcpy(verts[1].pos, &pos[3], 12); - memcpy(verts[3].pos, &pos[6], 12); - memcpy(verts[2].pos, &pos[9], 12); - memcpy(verts[0].uv, &texCoords[0], 8); - memcpy(verts[1].uv, &texCoords[2], 8); - memcpy(verts[3].uv, &texCoords[4], 8); - memcpy(verts[2].uv, &texCoords[6], 8); - - uint32_t bindOffset; - GLRBuffer *buffer; - - // Workaround: This might accidentally get called from ReportScreen screenshot-taking, and in that case - // the push buffer is not mapped. This only happens if framebuffer blit support is not available. - if (drawEngineGL_->GetPushVertexBuffer()->IsReady()) { - void *dest = drawEngineGL_->GetPushVertexBuffer()->Push(sizeof(verts), &bindOffset, &buffer); - memcpy(dest, verts, sizeof(verts)); - render_->BindVertexBuffer(simple2DInputLayout_, buffer, bindOffset); - render_->Draw(GL_TRIANGLE_STRIP, 0, 4); - } -} - void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) { _assert_msg_(nvfb->fbo, "Expecting a valid nvfb in UpdateDownloadTempBuffer"); diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 94b06155e0..fc69c77341 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -40,9 +40,6 @@ public: void SetShaderManager(ShaderManagerGLES *sm); void SetDrawEngine(DrawEngineGLES *td); - // x,y,w,h are relative to destW, destH which fill out the target completely. - void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override; - virtual void Init() override; void EndFrame(); void Resized() override; From 0f9bf47429b55d27fe59e07b0b0c100b3e8d37c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 12:39:53 +0200 Subject: [PATCH 18/35] Reimplement filtering in DrawActiveTexture --- GPU/Common/Draw2D.cpp | 12 ++++++++++-- GPU/Common/FramebufferManagerCommon.cpp | 3 ++- GPU/Common/FramebufferManagerCommon.h | 6 +++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 3f9ac35df4..a9ba00ab4f 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -57,7 +57,7 @@ void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) { } // verts have positions in clip coordinates. -void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount) { +void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter) { using namespace Draw; if (!draw2DPipelineLinear_) { @@ -112,12 +112,20 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver descLinear.wrapU = TextureAddressMode::CLAMP_TO_EDGE; descLinear.wrapV = TextureAddressMode::CLAMP_TO_EDGE; draw2DSamplerLinear_= draw_->CreateSamplerState(descLinear); + + SamplerStateDesc descNearest{}; + descLinear.magFilter = TextureFilter::NEAREST; + descLinear.minFilter = TextureFilter::NEAREST; + descLinear.mipFilter = TextureFilter::NEAREST; + descLinear.wrapU = TextureAddressMode::CLAMP_TO_EDGE; + descLinear.wrapV = TextureAddressMode::CLAMP_TO_EDGE; + draw2DSamplerNearest_ = draw_->CreateSamplerState(descNearest); } draw_->BindPipeline(draw2DPipelineLinear_); if (tex) { draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); } - draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &draw2DSamplerLinear_); + draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, linearFilter ? &draw2DSamplerLinear_ : &draw2DSamplerNearest_); draw_->DrawUP(verts, vertexCount); } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 1bdf8c0265..3c6315e863 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2495,6 +2495,7 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(stencilUploadSampler_); DoRelease(stencilUploadPipeline_); DoRelease(draw2DPipelineLinear_); + DoRelease(draw2DSamplerNearest_); DoRelease(draw2DSamplerLinear_); DoRelease(draw2DVs_); DoRelease(draw2DFs_); @@ -2555,7 +2556,7 @@ void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, floa // Rearrange to strip form. std::swap(coord[2], coord[3]); - DrawStrip2D(nullptr, coord, 4); + DrawStrip2D(nullptr, coord, 4, (flags & DRAWTEX_LINEAR) != 0); gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 9140ed18e9..86b1dd96a1 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -164,7 +164,6 @@ enum BindFramebufferColorFlags { enum DrawTextureFlags { DRAWTEX_NEAREST = 0, DRAWTEX_LINEAR = 1, - DRAWTEX_KEEP_STENCIL_ALPHA = 4, DRAWTEX_TO_BACKBUFFER = 8, }; @@ -354,10 +353,10 @@ protected: virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h); void SetViewport2D(int x, int y, int w, int h); Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height); - virtual void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags); + void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags); virtual void Bind2DShader() = 0; - void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount); + void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter); bool UpdateSize(); @@ -479,6 +478,7 @@ protected: // Draw2D pipelines Draw::Pipeline *draw2DPipelineLinear_ = nullptr; Draw::SamplerState *draw2DSamplerLinear_ = nullptr; + Draw::SamplerState *draw2DSamplerNearest_ = nullptr; Draw::ShaderModule *draw2DVs_ = nullptr; Draw::ShaderModule *draw2DFs_ = nullptr; }; From 8ded76650967b4462f0500616e74425eca07a87d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 14:31:24 +0200 Subject: [PATCH 19/35] UWP buildfix --- UWP/GPU_UWP/GPU_UWP.vcxproj | 2 ++ UWP/GPU_UWP/GPU_UWP.vcxproj.filters | 2 ++ 2 files changed, 4 insertions(+) diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj index 81ab4c82a0..acda27f60f 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj @@ -380,6 +380,7 @@ + @@ -439,6 +440,7 @@ + diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters index f1f1de951b..9dd217c598 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters @@ -57,6 +57,7 @@ + @@ -116,5 +117,6 @@ + \ No newline at end of file From d5a0249678e1f2cfbc52761c932b4415cb369943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 22:21:49 +0200 Subject: [PATCH 20/35] Fix upscaling in Vulkan. Fixes #15779 --- GPU/Vulkan/TextureCacheVulkan.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index dc2d0ecf87..50a2a48cb1 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -597,7 +597,8 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { VkFormat dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat()); - if (plan.hardwareScaling) { + if (plan.scaleFactor > 1) { + // Whether hardware or software scaling, this is the dest format. dstFmt = VULKAN_8888_FORMAT; } From 64a8a3f7d387693eea25801843b6f3dacfd873a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 15:27:55 +0200 Subject: [PATCH 21/35] D3D11: Remove more custom drawing --- GPU/Common/FramebufferManagerCommon.h | 1 - GPU/D3D11/FramebufferManagerD3D11.cpp | 33 ++++++--------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 86b1dd96a1..8fc8717ba9 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -327,7 +327,6 @@ public: SetColorUpdated(currentRenderVfb_, skipDrawReason); } } - void SetRenderSize(VirtualFramebuffer *vfb); void SetSafeSize(u16 w, u16 h); virtual void Resized(); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index b4b406d774..b5b7b4187e 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -216,40 +216,21 @@ void FramebufferManagerD3D11::SimpleBlit( float dY = 1.0f / (float)destH; float sX = 1.0f / (float)srcW; float sY = 1.0f / (float)srcH; - struct Vtx { - float x, y, z, u, v; + Draw2DVertex vtx[4] = { + { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY1), sX * srcX1, sY * srcY1 }, + { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY1), sX * srcX2, sY * srcY1 }, + { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY2), sX * srcX1, sY * srcY2 }, + { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY2), sX * srcX2, sY * srcY2 }, }; - Vtx vtx[4] = { - { -1.0f + 2.0f * dX * destX1, 1.0f - 2.0f * dY * destY1, 0.0f, sX * srcX1, sY * srcY1 }, - { -1.0f + 2.0f * dX * destX2, 1.0f - 2.0f * dY * destY1, 0.0f, sX * srcX2, sY * srcY1 }, - { -1.0f + 2.0f * dX * destX1, 1.0f - 2.0f * dY * destY2, 0.0f, sX * srcX1, sY * srcY2 }, - { -1.0f + 2.0f * dX * destX2, 1.0f - 2.0f * dY * destY2, 0.0f, sX * srcX2, sY * srcY2 }, - }; - - D3D11_MAPPED_SUBRESOURCE map; - ASSERT_SUCCESS(context_->Map(quadBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map)); - memcpy(map.pData, vtx, 4 * sizeof(Vtx)); - context_->Unmap(quadBuffer_, 0); // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). draw_->BindTexture(0, nullptr); draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "SimpleBlit"); draw_->BindFramebufferAsTexture(src, 0, Draw::FB_COLOR_BIT, 0); - Bind2DShader(); - D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)destW, (float)destH, 0.0f, 1.0f }; - context_->RSSetViewports(1, &vp); - context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); - context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0); - context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context_->PSSetSamplers(0, 1, linearFilter ? &stockD3D11.samplerLinear2DClamp : &stockD3D11.samplerPoint2DClamp); - UINT stride = sizeof(Vtx); - UINT offset = 0; - context_->IASetVertexBuffers(0, 1, &quadBuffer_, &stride, &offset); - context_->Draw(4, 0); + DrawStrip2D(nullptr, vtx, 4, linearFilter); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); } void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { From 1ab9293cb3071f41a271193ff5db7a3b64829ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 15:41:17 +0200 Subject: [PATCH 22/35] Convert FramebufferBlit from the GL backend to use thin3d --- GPU/Common/FramebufferManagerCommon.cpp | 104 ++++++++++++++++++++++++ GPU/Common/FramebufferManagerCommon.h | 7 +- GPU/D3D11/FramebufferManagerD3D11.cpp | 35 -------- GPU/D3D11/FramebufferManagerD3D11.h | 4 - GPU/GLES/FramebufferManagerGLES.cpp | 85 ------------------- GPU/GLES/FramebufferManagerGLES.h | 3 - 6 files changed, 110 insertions(+), 128 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 3c6315e863..52c328b90d 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2560,3 +2560,107 @@ void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, floa gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); } + +void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { + if (!dst->fbo || !src->fbo || !useBufferedRendering_) { + // This can happen if they recently switched from non-buffered. + if (useBufferedRendering_) { + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); + } + return; + } + + bool useBlit = draw_->GetDeviceCaps().framebufferBlitSupported; + bool useCopy = draw_->GetDeviceCaps().framebufferCopySupported; + if (dst == currentRenderVfb_) { + // If already bound, using either a blit or a copy is unlikely to be an optimization. + useBlit = false; + useCopy = false; + } + + float srcXFactor = useBlit ? src->renderScaleFactor : 1.0f; + float srcYFactor = useBlit ? src->renderScaleFactor : 1.0f; + const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; + if (srcBpp != bpp && bpp != 0) { + srcXFactor = (srcXFactor * bpp) / srcBpp; + } + int srcX1 = srcX * srcXFactor; + int srcX2 = (srcX + w) * srcXFactor; + int srcY1 = srcY * srcYFactor; + int srcY2 = (srcY + h) * srcYFactor; + + float dstXFactor = useBlit ? dst->renderScaleFactor : 1.0f; + float dstYFactor = useBlit ? dst->renderScaleFactor : 1.0f; + const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; + if (dstBpp != bpp && bpp != 0) { + dstXFactor = (dstXFactor * bpp) / dstBpp; + } + int dstX1 = dstX * dstXFactor; + int dstX2 = (dstX + w) * dstXFactor; + int dstY1 = dstY * dstYFactor; + int dstY2 = (dstY + h) * dstYFactor; + + if (src == dst && srcX == dstX && srcY == dstY) { + // Let's just skip a copy where the destination is equal to the source. + WARN_LOG_REPORT_ONCE(blitSame, G3D, "Skipped blit with equal dst and src"); + return; + } + + if (useCopy) { + // glBlitFramebuffer can clip, but glCopyImageSubData is more restricted. + // In case the src goes outside, we just skip the optimization in that case. + const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1; + const bool srcInsideBounds = srcX2 <= src->renderWidth && srcY2 <= src->renderHeight; + const bool dstInsideBounds = dstX2 <= dst->renderWidth && dstY2 <= dst->renderHeight; + const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; + const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; + if (sameSize && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { + draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, tag); + return; + } + } + + if (useBlit) { + draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); + } else { + BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false); + } + + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); +} + +void FramebufferManagerCommon::BlitUsingRaster( + Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, + Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, + bool linearFilter) { + + int destW, destH, srcW, srcH; + draw_->GetFramebufferDimensions(src, &srcW, &srcH); + draw_->GetFramebufferDimensions(dest, &destW, &destH); + + if (srcW == destW && srcH == destH && destX2 - destX1 == srcX2 - srcX1 && destY2 - destY1 == srcY2 - srcY1) { + // Optimize to a copy + draw_->CopyFramebufferImage(src, 0, (int)srcX1, (int)srcY1, 0, dest, 0, (int)destX1, (int)destY1, 0, (int)(srcX2 - srcX1), (int)(srcY2 - srcY1), 1, Draw::FB_COLOR_BIT, "BlitUsingRaster"); + return; + } + + float dX = 1.0f / (float)destW; + float dY = 1.0f / (float)destH; + float sX = 1.0f / (float)srcW; + float sY = 1.0f / (float)srcH; + Draw2DVertex vtx[4] = { + { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY1), sX * srcX1, sY * srcY1 }, + { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY1), sX * srcX2, sY * srcY1 }, + { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY2), sX * srcX1, sY * srcY2 }, + { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY2), sX * srcX2, sY * srcY2 }, + }; + + // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). + draw_->BindTexture(0, nullptr); + draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitUsingRaster"); + draw_->BindFramebufferAsTexture(src, 0, Draw::FB_COLOR_BIT, 0); + + DrawStrip2D(nullptr, vtx, 4, linearFilter); + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); +} diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 8fc8717ba9..2f09440b56 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -363,7 +363,12 @@ protected: virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra // Used by ReadFramebufferToMemory and later framebuffer block copies - virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) = 0; + virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag); + + void BlitUsingRaster( + Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, + Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, bool linearFilter); + void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags); void EstimateDrawingSize(u32 fb_address, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int fb_stride, int &drawing_width, int &drawing_height); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index b5b7b4187e..72622d3ee6 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -198,41 +198,6 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { } } -void FramebufferManagerD3D11::SimpleBlit( - Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, - Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, bool linearFilter) { - - int destW, destH, srcW, srcH; - draw_->GetFramebufferDimensions(src, &srcW, &srcH); - draw_->GetFramebufferDimensions(dest, &destW, &destH); - - if (srcW == destW && srcH == destH && destX2 - destX1 == srcX2 - srcX1 && destY2 - destY1 == srcY2 - srcY1) { - // Optimize to a copy - draw_->CopyFramebufferImage(src, 0, (int)srcX1, (int)srcY1, 0, dest, 0, (int)destX1, (int)destY1, 0, (int)(srcX2 - srcX1), (int)(srcY2 - srcY1), 1, Draw::FB_COLOR_BIT, "SimpleBlit"); - return; - } - - float dX = 1.0f / (float)destW; - float dY = 1.0f / (float)destH; - float sX = 1.0f / (float)srcW; - float sY = 1.0f / (float)srcH; - Draw2DVertex vtx[4] = { - { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY1), sX * srcX1, sY * srcY1 }, - { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY1), sX * srcX2, sY * srcY1 }, - { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY2), sX * srcX1, sY * srcY2 }, - { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY2), sX * srcX2, sY * srcY2 }, - }; - - // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). - draw_->BindTexture(0, nullptr); - draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "SimpleBlit"); - draw_->BindFramebufferAsTexture(src, 0, Draw::FB_COLOR_BIT, 0); - - DrawStrip2D(nullptr, vtx, 4, linearFilter); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); -} - void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { if (!dst->fbo || !src->fbo || !useBufferedRendering_) { // This can happen if they recently switched from non-buffered. diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 38d0d6623b..2d37fb26e9 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -54,10 +54,6 @@ protected: private: void Bind2DShader() override; void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); - void SimpleBlit( - Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, - Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, - bool linearFilter); ID3D11Device *device_; ID3D11DeviceContext *context_; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 0e8077e60f..8d1bcc629d 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -174,91 +174,6 @@ void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) } } -void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { - if (!dst->fbo || !src->fbo || !useBufferedRendering_) { - // This can happen if they recently switched from non-buffered. - if (useBufferedRendering_) - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); - return; - } - - bool useBlit = draw_->GetDeviceCaps().framebufferBlitSupported; - bool useCopy = draw_->GetDeviceCaps().framebufferCopySupported; - if (dst == currentRenderVfb_) { - // If already bound, using either a blit or a copy is unlikely to be an optimization. - useBlit = false; - useCopy = false; - } - - float srcXFactor = useBlit ? src->renderScaleFactor : 1.0f; - float srcYFactor = useBlit ? src->renderScaleFactor : 1.0f; - const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; - if (srcBpp != bpp && bpp != 0) { - srcXFactor = (srcXFactor * bpp) / srcBpp; - } - int srcX1 = srcX * srcXFactor; - int srcX2 = (srcX + w) * srcXFactor; - int srcY1 = srcY * srcYFactor; - int srcY2 = (srcY + h) * srcYFactor; - - float dstXFactor = useBlit ? dst->renderScaleFactor : 1.0f; - float dstYFactor = useBlit ? dst->renderScaleFactor : 1.0f; - const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; - if (dstBpp != bpp && bpp != 0) { - dstXFactor = (dstXFactor * bpp) / dstBpp; - } - int dstX1 = dstX * dstXFactor; - int dstX2 = (dstX + w) * dstXFactor; - int dstY1 = dstY * dstYFactor; - int dstY2 = (dstY + h) * dstYFactor; - - if (src == dst && srcX == dstX && srcY == dstY) { - // Let's just skip a copy where the destination is equal to the source. - WARN_LOG_REPORT_ONCE(blitSame, G3D, "Skipped blit with equal dst and src"); - return; - } - - if (useCopy && draw_->GetDeviceCaps().framebufferCopySupported) { - // glBlitFramebuffer can clip, but glCopyImageSubData is more restricted. - // In case the src goes outside, we just skip the optimization in that case. - const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1; - const bool srcInsideBounds = srcX2 <= src->renderWidth && srcY2 <= src->renderHeight; - const bool dstInsideBounds = dstX2 <= dst->renderWidth && dstY2 <= dst->renderHeight; - const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; - const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; - if (sameSize && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { - draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, tag); - return; - } - } - - if (useBlit) { - draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); - } else { - // TODO: Use thin3d for this, instead of dirtying up the code here. - draw_->BindFramebufferAsRenderTarget(dst->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); - draw_->BindFramebufferAsTexture(src->fbo, 0, Draw::FB_COLOR_BIT, 0); - - // Make sure our 2D drawing program is ready. Compiles only if not already compiled. - CompileDraw2DProgram(); - - render_->SetViewport({ 0, 0, (float)dst->renderWidth, (float)dst->renderHeight, 0, 1.0f }); - render_->SetStencilDisabled(); - render_->SetDepth(false, false, GL_ALWAYS); - render_->SetNoBlendAndMask(0xF); - - // The first four coordinates are relative to the 6th and 7th arguments of DrawActiveTexture. - // Should maybe revamp that interface. - float srcW = src->bufferWidth; - float srcH = src->bufferHeight; - render_->BindProgram(draw2dprogram_); - DrawActiveTexture(dstX1, dstY1, w * dstXFactor, h * dstYFactor, dst->bufferWidth, dst->bufferHeight, srcX1 / srcW, srcY1 / srcH, srcX2 / srcW, srcY2 / srcH, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); - textureCache_->ForgetLastTexture(); - } - - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); -} - void FramebufferManagerGLES::EndFrame() { } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index fc69c77341..349b5a23e6 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -50,9 +50,6 @@ public: bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; protected: - // Used by ReadFramebufferToMemory and later framebuffer block copies - void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) override; - void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; private: From 9d23939e282fa96fcce06c807d0481456dcfeed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 15:49:17 +0200 Subject: [PATCH 23/35] Replace D3D11's BlitFramebuffer with the common one --- GPU/Common/FramebufferManagerCommon.cpp | 8 ++++- GPU/D3D11/FramebufferManagerD3D11.cpp | 46 ------------------------- GPU/D3D11/FramebufferManagerD3D11.h | 4 --- 3 files changed, 7 insertions(+), 51 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 52c328b90d..812fd33696 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2623,7 +2623,13 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX if (useBlit) { draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); } else { - BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false); + Draw::Framebuffer *srcFBO = src->fbo; + if (src == dst) { + Draw::Framebuffer *tempFBO = GetTempFBO(TempFBO::BLIT, src->renderWidth, src->renderHeight); + BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, tempFBO, dstX1, dstY1, dstX2, dstY2, false); + srcFBO = tempFBO; + } + BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false); } gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 72622d3ee6..a53aea9540 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -198,52 +198,6 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { } } -void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { - if (!dst->fbo || !src->fbo || !useBufferedRendering_) { - // This can happen if they recently switched from non-buffered. - if (useBufferedRendering_) { - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer_Fail"); - } - return; - } - - float srcXFactor = src->renderScaleFactor; - float srcYFactor = src->renderScaleFactor; - const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; - if (srcBpp != bpp && bpp != 0) { - srcXFactor = (srcXFactor * bpp) / srcBpp; - } - int srcX1 = srcX * srcXFactor; - int srcX2 = (srcX + w) * srcXFactor; - int srcY1 = srcY * srcYFactor; - int srcY2 = (srcY + h) * srcYFactor; - - float dstXFactor = dst->renderScaleFactor; - float dstYFactor = dst->renderScaleFactor; - const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; - if (dstBpp != bpp && bpp != 0) { - dstXFactor = (dstXFactor * bpp) / dstBpp; - } - int dstX1 = dstX * dstXFactor; - int dstX2 = (dstX + w) * dstXFactor; - int dstY1 = dstY * dstYFactor; - int dstY2 = (dstY + h) * dstYFactor; - - // Direct3D doesn't support rect -> self. - Draw::Framebuffer *srcFBO = src->fbo; - if (src == dst) { - Draw::Framebuffer *tempFBO = GetTempFBO(TempFBO::BLIT, src->renderWidth, src->renderHeight); - SimpleBlit(tempFBO, dstX1, dstY1, dstX2, dstY2, src->fbo, srcX1, srcY1, srcX2, srcY2, false); - srcFBO = tempFBO; - } - SimpleBlit( - dst->fbo, dstX1, dstY1, dstX2, dstY2, - srcFBO, srcX1, srcY1, srcX2, srcY2, - false); - - draw_->BindTexture(0, nullptr); -} - // Nobody calls this yet. void FramebufferManagerD3D11::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { if (!vfb->fbo) { diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 2d37fb26e9..cc4a67bbd1 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -47,10 +47,6 @@ public: return quadBuffer_; } -protected: - // Used by ReadFramebufferToMemory and later framebuffer block copies - void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) override; - private: void Bind2DShader() override; void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); From 126ace770efe2ed5915f598942be008da6c6a81e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 16:00:19 +0200 Subject: [PATCH 24/35] Remove the D3D9 and Vulkan BlitFramebuffer functions --- GPU/Common/FramebufferManagerCommon.cpp | 22 ++++++++ GPU/Directx9/FramebufferManagerDX9.cpp | 51 ------------------ GPU/Directx9/FramebufferManagerDX9.h | 3 -- GPU/Vulkan/FramebufferManagerVulkan.cpp | 72 ------------------------- GPU/Vulkan/FramebufferManagerVulkan.h | 3 -- 5 files changed, 22 insertions(+), 129 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 812fd33696..03666ff0f3 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2570,10 +2570,32 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX return; } + // Perform a little bit of clipping first. + // Block transfer coords are unsigned so I don't think we need to clip on the left side.. Although there are + // other uses for BlitFramebuffer. + if (dstX + w > dst->bufferWidth) { + w -= dstX + w - dst->bufferWidth; + } + if (dstY + h > dst->bufferHeight) { + h -= dstY + h - dst->bufferHeight; + } + if (srcX + w > src->bufferWidth) { + w -= srcX + w - src->bufferWidth; + } + if (srcY + h > src->bufferHeight) { + h -= srcY + h - src->bufferHeight; + } + + if (w <= 0 || h <= 0) { + // The whole rectangle got clipped. + return; + } + bool useBlit = draw_->GetDeviceCaps().framebufferBlitSupported; bool useCopy = draw_->GetDeviceCaps().framebufferCopySupported; if (dst == currentRenderVfb_) { // If already bound, using either a blit or a copy is unlikely to be an optimization. + // So we're gonna use a raster draw instead. useBlit = false; useCopy = false; } diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index 681cd3accb..1386427db3 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -189,57 +189,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { return offscreen; } - void FramebufferManagerDX9::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { - if (!dst->fbo || !src->fbo || !useBufferedRendering_) { - // This can happen if we recently switched from non-buffered. - if (useBufferedRendering_) - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer_Fail"); - return; - } - - float srcXFactor = (float)src->renderScaleFactor; - float srcYFactor = (float)src->renderScaleFactor; - const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; - if (srcBpp != bpp && bpp != 0) { - srcXFactor = (srcXFactor * bpp) / srcBpp; - } - int srcX1 = srcX * srcXFactor; - int srcX2 = (srcX + w) * srcXFactor; - int srcY1 = srcY * srcYFactor; - int srcY2 = (srcY + h) * srcYFactor; - - float dstXFactor = (float)dst->renderScaleFactor; - float dstYFactor = (float)dst->renderScaleFactor; - const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; - if (dstBpp != bpp && bpp != 0) { - dstXFactor = (dstXFactor * bpp) / dstBpp; - } - int dstX1 = dstX * dstXFactor; - int dstX2 = (dstX + w) * dstXFactor; - int dstY1 = dstY * dstYFactor; - int dstY2 = (dstY + h) * dstYFactor; - - // Direct3D 9 doesn't support rect -> self. - Draw::Framebuffer *srcFBO = src->fbo; - if (src == dst) { - Draw::Framebuffer *tempFBO = GetTempFBO(TempFBO::BLIT, src->renderWidth, src->renderHeight); - bool result = draw_->BlitFramebuffer( - src->fbo, srcX1, srcY1, srcX2, srcY2, - tempFBO, dstX1, dstY1, dstX2, dstY2, - Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); - if (result) { - srcFBO = tempFBO; - } - } - bool result = draw_->BlitFramebuffer( - srcFBO, srcX1, srcY1, srcX2, srcY2, - dst->fbo, dstX1, dstY1, dstX2, dstY2, - Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); - if (!result) { - ERROR_LOG_REPORT(G3D, "fbo_blit_color failed in blit (%08x -> %08x)", src->fb_address, dst->fb_address); - } - } - void ConvertFromBGRA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 width, u32 height, GEBufferFormat format) { // Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP. const u32 *src32 = (const u32 *)src; diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index 2cc4371c92..9340aaf971 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -59,9 +59,6 @@ protected: void Bind2DShader() override; void DecimateFBOs() override; - // Used by ReadFramebufferToMemory and later framebuffer block copies - void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) override; - private: void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) override; void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); diff --git a/GPU/Vulkan/FramebufferManagerVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp index b0dd6e956d..0cb6334016 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.cpp +++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp @@ -175,78 +175,6 @@ void FramebufferManagerVulkan::Bind2DShader() { cur2DPipeline_ = vulkan2D_->GetPipeline(rp, vsBasicTex_, fsBasicTex_); } -void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { - if (!dst->fbo || !src->fbo || !useBufferedRendering_) { - // This can happen if they recently switched from non-buffered. - if (useBufferedRendering_) { - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer_Fail"); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); - } - return; - } - - // Perform a little bit of clipping first. - // Block transfer coords are unsigned so I don't think we need to clip on the left side.. - if (dstX + w > dst->bufferWidth) { - w -= dstX + w - dst->bufferWidth; - } - if (dstY + h > dst->bufferHeight) { - h -= dstY + h - dst->bufferHeight; - } - if (srcX + w > src->bufferWidth) { - w -= srcX + w - src->bufferWidth; - } - if (srcY + h > src->bufferHeight) { - h -= srcY + h - src->bufferHeight; - } - - if (w <= 0 || h <= 0) { - // The whole rectangle got clipped. - return; - } - - float srcXFactor = (float)src->renderScaleFactor; - float srcYFactor = (float)src->renderScaleFactor; - - // Some games use wrong-format block transfers. Simulate that. - const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; - if (srcBpp != bpp && bpp != 0) { - srcXFactor = (srcXFactor * bpp) / srcBpp; - } - int srcX1 = srcX * srcXFactor; - int srcX2 = (srcX + w) * srcXFactor; - int srcY1 = srcY * srcYFactor; - int srcY2 = (srcY + h) * srcYFactor; - - float dstXFactor = (float)dst->renderScaleFactor; - float dstYFactor = (float)dst->renderScaleFactor; - const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; - if (dstBpp != bpp && bpp != 0) { - dstXFactor = (dstXFactor * bpp) / dstBpp; - } - int dstX1 = dstX * dstXFactor; - int dstX2 = (dstX + w) * dstXFactor; - int dstY1 = dstY * dstYFactor; - int dstY2 = (dstY + h) * dstYFactor; - - if (src == dst && srcX == dstX && srcY == dstY) { - // Let's just skip a copy where the destination is equal to the source. - WARN_LOG_REPORT_ONCE(blitSame, G3D, "Skipped blit with equal dst and src"); - return; - } - - const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1; - const bool srcInsideBounds = srcX2 <= src->renderWidth && srcY2 <= src->renderHeight; - const bool dstInsideBounds = dstX2 <= dst->renderWidth && dstY2 <= dst->renderHeight; - const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; - const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; - if (sameSize && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { - draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, tag); - } else { - draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); - } -} - void FramebufferManagerVulkan::BeginFrameVulkan() { BeginFrame(); } diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h index 6f60b12652..ad2f1df879 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -56,9 +56,6 @@ public: protected: void Bind2DShader() override; - // Used by ReadFramebufferToMemory and later framebuffer block copies - void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) override; - private: void InitDeviceObjects(); void DestroyDeviceObjects(); From f8e0c0946349360ddefb6ddde05d1fca02d7a736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 17:12:57 +0200 Subject: [PATCH 25/35] Delete unused stuff in all backends --- GPU/Common/FramebufferManagerCommon.cpp | 1 - GPU/Common/FramebufferManagerCommon.h | 1 - GPU/D3D11/FramebufferManagerD3D11.cpp | 61 ---------------------- GPU/D3D11/FramebufferManagerD3D11.h | 8 --- GPU/Directx9/FramebufferManagerDX9.cpp | 69 ------------------------- GPU/Directx9/FramebufferManagerDX9.h | 11 +--- GPU/GLES/FramebufferManagerGLES.cpp | 44 ---------------- GPU/GLES/FramebufferManagerGLES.h | 13 ----- GPU/Vulkan/FramebufferManagerVulkan.cpp | 47 ----------------- GPU/Vulkan/FramebufferManagerVulkan.h | 15 ------ 10 files changed, 1 insertion(+), 269 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 03666ff0f3..e0dca3b3cc 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -978,7 +978,6 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int Draw::Texture *pixelsTex = MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height); if (pixelsTex) { draw_->BindTextures(0, 1, &pixelsTex); - Bind2DShader(); DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); gpuStats.numUploads++; pixelsTex->Release(); diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 2f09440b56..f0b981ec1d 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -353,7 +353,6 @@ protected: void SetViewport2D(int x, int y, int w, int h); Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height); void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags); - virtual void Bind2DShader() = 0; void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index a53aea9540..982e0f7eeb 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -43,65 +43,16 @@ #include #endif -static const char *vscode = - "struct VS_IN {\n" - " float4 ObjPos : POSITION;\n" - " float2 Uv : TEXCOORD0;\n" - "};\n" - "struct VS_OUT {\n" - " float2 Uv : TEXCOORD0;\n" - " float4 ProjPos : SV_Position;\n" - "};\n" - "VS_OUT main(VS_IN In) {\n" - " VS_OUT Out;\n" - " Out.ProjPos = In.ObjPos;\n" - " Out.Uv = In.Uv;\n" - " return Out;\n" - "}\n"; - -static const char *pscode = - "SamplerState samp : register(s0);\n" - "Texture2D tex : register(t0);\n" - "struct PS_IN {\n" - " float2 Uv : TEXCOORD0;\n" - "};\n" - "float4 main( PS_IN In ) : SV_Target {\n" - " float4 c = tex.Sample(samp, In.Uv);\n" - " return c;\n" - "}\n"; - -const D3D11_INPUT_ELEMENT_DESC FramebufferManagerD3D11::g_QuadVertexElements[2] = { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, }, -}; - FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) : FramebufferManagerCommon(draw) { device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE); context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); featureLevel_ = (D3D_FEATURE_LEVEL)draw->GetNativeObject(Draw::NativeObject::FEATURE_LEVEL); - std::vector bytecode; - - std::string errorMsg; - quadVertexShader_ = CreateVertexShaderD3D11(device_, vscode, strlen(vscode), &bytecode, featureLevel_); - quadPixelShader_ = CreatePixelShaderD3D11(device_, pscode, strlen(pscode), featureLevel_); - ASSERT_SUCCESS(device_->CreateInputLayout(g_QuadVertexElements, ARRAY_SIZE(g_QuadVertexElements), bytecode.data(), bytecode.size(), &quadInputLayout_)); - - // STRIP geometry - static const float fsCoord[20] = { - -1.0f,-1.0f, 0.0f, 0.0f, 0.0f, - 1.0f,-1.0f, 0.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, - }; D3D11_BUFFER_DESC vb{}; vb.ByteWidth = 20 * 4; vb.Usage = D3D11_USAGE_IMMUTABLE; - vb.CPUAccessFlags = 0; vb.BindFlags = D3D11_BIND_VERTEX_BUFFER; - D3D11_SUBRESOURCE_DATA data{ fsCoord }; - ASSERT_SUCCESS(device_->CreateBuffer(&vb, &data, &fsQuadBuffer_)); vb.Usage = D3D11_USAGE_DYNAMIC; vb.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; ASSERT_SUCCESS(device_->CreateBuffer(&vb, nullptr, &quadBuffer_)); @@ -127,13 +78,7 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) FramebufferManagerD3D11::~FramebufferManagerD3D11() { // Drawing cleanup - if (quadVertexShader_) - quadVertexShader_->Release(); - if (quadPixelShader_) - quadPixelShader_->Release(); - quadInputLayout_->Release(); quadBuffer_->Release(); - fsQuadBuffer_->Release(); // Stencil cleanup for (int i = 0; i < 256; i++) { @@ -167,12 +112,6 @@ void FramebufferManagerD3D11::SetDrawEngine(DrawEngineD3D11 *td) { drawEngine_ = td; } -void FramebufferManagerD3D11::Bind2DShader() { - context_->IASetInputLayout(quadInputLayout_); - context_->PSSetShader(quadPixelShader_, 0, 0); - context_->VSSetShader(quadVertexShader_, 0, 0); -} - static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { size_t x = 0; diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index cc4a67bbd1..dc46158cc4 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -48,22 +48,14 @@ public: } private: - void Bind2DShader() override; void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); ID3D11Device *device_; ID3D11DeviceContext *context_; D3D_FEATURE_LEVEL featureLevel_; - ID3D11VertexShader *quadVertexShader_; - ID3D11PixelShader *quadPixelShader_; - ID3D11InputLayout *quadInputLayout_; // Dynamic ID3D11Buffer *quadBuffer_; - ID3D11Buffer *fsQuadBuffer_; - const UINT quadStride_ = 20; - const UINT quadOffset_ = 0; - static const D3D11_INPUT_ELEMENT_DESC g_QuadVertexElements[2]; ID3D11PixelShader *stencilUploadPS_ = nullptr; ID3D11VertexShader *stencilUploadVS_ = nullptr; diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index 1386427db3..aec99b20c3 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -47,59 +47,11 @@ namespace DX9 { -static const char *vscode = R"( -struct VS_IN { - float4 ObjPos : POSITION; - float2 Uv : TEXCOORD0; -}; -struct VS_OUT { - float4 ProjPos : POSITION; - float2 Uv : TEXCOORD0; -}; -VS_OUT main( VS_IN In ) { - VS_OUT Out; - Out.ProjPos = In.ObjPos; - Out.Uv = In.Uv; - return Out; -} -)"; - -static const char *pscode = R"( -sampler s: register(s0); -struct PS_IN { - float2 Uv : TEXCOORD0; -}; -float4 main( PS_IN In ) : COLOR { - float4 c = tex2D(s, In.Uv); - return c; -} -)"; - -static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { - { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, - { 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, - D3DDECL_END() -}; - FramebufferManagerDX9::FramebufferManagerDX9(Draw::DrawContext *draw) : FramebufferManagerCommon(draw) { device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE); deviceEx_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE_EX); - std::string errorMsg; - if (!CompileVertexShaderD3D9(device_, vscode, &pFramebufferVertexShader, &errorMsg)) { - OutputDebugStringA(errorMsg.c_str()); - } - - if (!CompilePixelShaderD3D9(device_, pscode, &pFramebufferPixelShader, &errorMsg)) { - OutputDebugStringA(errorMsg.c_str()); - if (pFramebufferVertexShader) { - pFramebufferVertexShader->Release(); - } - } - - device_->CreateVertexDeclaration(g_FramebufferVertexElements, &pFramebufferVertexDecl); - int usage = 0; D3DPOOL pool = D3DPOOL_MANAGED; @@ -118,24 +70,9 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { } FramebufferManagerDX9::~FramebufferManagerDX9() { - if (pFramebufferVertexShader) { - pFramebufferVertexShader->Release(); - pFramebufferVertexShader = nullptr; - } - if (pFramebufferPixelShader) { - pFramebufferPixelShader->Release(); - pFramebufferPixelShader = nullptr; - } - pFramebufferVertexDecl->Release(); for (auto &it : offscreenSurfaces_) { it.second.surface->Release(); } - if (stencilUploadPS_) { - stencilUploadPS_->Release(); - } - if (stencilUploadVS_) { - stencilUploadVS_->Release(); - } if (nullTex_) nullTex_->Release(); } @@ -152,12 +89,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { drawEngine_ = td; } - void FramebufferManagerDX9::Bind2DShader() { - device_->SetVertexDeclaration(pFramebufferVertexDecl); - device_->SetPixelShader(pFramebufferPixelShader); - device_->SetVertexShader(pFramebufferVertexShader); - } - LPDIRECT3DSURFACE9 FramebufferManagerDX9::GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface, VirtualFramebuffer *vfb) { D3DSURFACE_DESC desc = {}; HRESULT hr = similarSurface->GetDesc(&desc); diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index 9340aaf971..c39b032fcd 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -56,7 +56,6 @@ public: LPDIRECT3DSURFACE9 GetOffscreenSurface(D3DFORMAT fmt, u32 w, u32 h); protected: - void Bind2DShader() override; void DecimateFBOs() override; private: @@ -67,14 +66,6 @@ private: LPDIRECT3DDEVICE9 device_; LPDIRECT3DDEVICE9 deviceEx_; - LPDIRECT3DVERTEXSHADER9 pFramebufferVertexShader = nullptr; - LPDIRECT3DPIXELSHADER9 pFramebufferPixelShader = nullptr; - LPDIRECT3DVERTEXDECLARATION9 pFramebufferVertexDecl = nullptr; - - LPDIRECT3DPIXELSHADER9 stencilUploadPS_ = nullptr; - LPDIRECT3DVERTEXSHADER9 stencilUploadVS_ = nullptr; - bool stencilUploadFailed_ = false; - LPDIRECT3DTEXTURE9 nullTex_ = nullptr; struct OffscreenSurface { @@ -85,4 +76,4 @@ private: std::unordered_map offscreenSurfaces_; }; -}; +} diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 8d1bcc629d..d4ad9dadd4 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -70,33 +70,6 @@ void main() { } )"; -void FramebufferManagerGLES::CompileDraw2DProgram() { - if (!draw2dprogram_) { - std::string errorString; - static std::string vs_code, fs_code; - vs_code = ApplyGLSLPrelude(basic_vs, GL_VERTEX_SHADER); - fs_code = ApplyGLSLPrelude(tex_fs, GL_FRAGMENT_SHADER); - std::vector shaders; - shaders.push_back(render_->CreateShader(GL_VERTEX_SHADER, vs_code, "draw2d")); - shaders.push_back(render_->CreateShader(GL_FRAGMENT_SHADER, fs_code, "draw2d")); - - std::vector queries; - queries.push_back({ &u_draw2d_tex, "u_tex" }); - std::vector initializers; - initializers.push_back({ &u_draw2d_tex, 0 }); - std::vector semantics; - semantics.push_back({ 0, "a_position" }); - semantics.push_back({ 1, "a_texcoord0" }); - draw2dprogram_ = render_->CreateProgram(shaders, semantics, queries, initializers, false, false); - for (auto shader : shaders) - render_->DeleteShader(shader); - } -} - -void FramebufferManagerGLES::Bind2DShader() { - render_->BindProgram(draw2dprogram_); -} - FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render) : FramebufferManagerCommon(draw), render_(render) @@ -109,7 +82,6 @@ FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRender void FramebufferManagerGLES::Init() { FramebufferManagerCommon::Init(); - CompileDraw2DProgram(); } void FramebufferManagerGLES::SetTextureCache(TextureCacheGLES *tc) { @@ -126,25 +98,9 @@ void FramebufferManagerGLES::SetDrawEngine(DrawEngineGLES *td) { } void FramebufferManagerGLES::CreateDeviceObjects() { - CompileDraw2DProgram(); - - std::vector entries; - entries.push_back({ 0, 3, GL_FLOAT, GL_FALSE, sizeof(Simple2DVertex), offsetof(Simple2DVertex, pos) }); - entries.push_back({ 1, 2, GL_FLOAT, GL_FALSE, sizeof(Simple2DVertex), offsetof(Simple2DVertex, uv) }); - simple2DInputLayout_ = render_->CreateInputLayout(entries); } void FramebufferManagerGLES::DestroyDeviceObjects() { - if (simple2DInputLayout_) { - render_->DeleteInputLayout(simple2DInputLayout_); - simple2DInputLayout_ = nullptr; - } - - if (draw2dprogram_) { - render_->DeleteProgram(draw2dprogram_); - draw2dprogram_ = nullptr; - } - if (stencilUploadPipeline_) { stencilUploadPipeline_->Release(); stencilUploadPipeline_ = nullptr; diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 349b5a23e6..adbd1b8ddf 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -56,9 +56,6 @@ private: void CreateDeviceObjects(); void DestroyDeviceObjects(); - void Bind2DShader() override; - void CompileDraw2DProgram(); - void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); GLRenderManager *render_; @@ -66,22 +63,12 @@ private: u8 *convBuf_ = nullptr; u32 convBufSize_ = 0; - GLRProgram *draw2dprogram_ = nullptr; - GLRProgram *depthDownloadProgram_ = nullptr; int u_depthDownloadTex = -1; int u_depthDownloadFactor = -1; int u_depthDownloadShift = -1; int u_depthDownloadTo8 = -1; - // Cached uniform locs - int u_draw2d_tex = -1; - DrawEngineGLES *drawEngineGL_ = nullptr; - struct Simple2DVertex { - float pos[3]; - float uv[2]; - }; - GLRInputLayout *simple2DInputLayout_ = nullptr; }; diff --git a/GPU/Vulkan/FramebufferManagerVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp index 0cb6334016..25107040c2 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.cpp +++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp @@ -100,52 +100,10 @@ void FramebufferManagerVulkan::SetDrawEngine(DrawEngineVulkan *td) { } void FramebufferManagerVulkan::InitDeviceObjects() { - VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); - std::string fs_errors, vs_errors; - fsBasicTex_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, tex_fs, &fs_errors); - vsBasicTex_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_VERTEX_BIT, tex_vs, &vs_errors); - _assert_(fsBasicTex_ != VK_NULL_HANDLE); - _assert_(vsBasicTex_ != VK_NULL_HANDLE); - - VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; - samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samp.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samp.magFilter = VK_FILTER_NEAREST; - samp.minFilter = VK_FILTER_NEAREST; - VkResult res = vkCreateSampler(vulkan->GetDevice(), &samp, nullptr, &nearestSampler_); - _assert_(res == VK_SUCCESS); - samp.magFilter = VK_FILTER_LINEAR; - samp.minFilter = VK_FILTER_LINEAR; - res = vkCreateSampler(vulkan->GetDevice(), &samp, nullptr, &linearSampler_); - _assert_(res == VK_SUCCESS); } void FramebufferManagerVulkan::DestroyDeviceObjects() { - if (!draw_) - return; - VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); - if (fsBasicTex_ != VK_NULL_HANDLE) { - vulkan2D_->PurgeFragmentShader(fsBasicTex_); - vulkan->Delete().QueueDeleteShaderModule(fsBasicTex_); - } - if (vsBasicTex_ != VK_NULL_HANDLE) { - vulkan2D_->PurgeVertexShader(vsBasicTex_); - vulkan->Delete().QueueDeleteShaderModule(vsBasicTex_); - } - if (stencilFs_ != VK_NULL_HANDLE) { - vulkan2D_->PurgeFragmentShader(stencilFs_); - vulkan->Delete().QueueDeleteShaderModule(stencilFs_); - } - if (stencilVs_ != VK_NULL_HANDLE) { - vulkan2D_->PurgeVertexShader(stencilVs_); - vulkan->Delete().QueueDeleteShaderModule(stencilVs_); - } - if (linearSampler_ != VK_NULL_HANDLE) - vulkan->Delete().QueueDeleteSampler(linearSampler_); - if (nearestSampler_ != VK_NULL_HANDLE) - vulkan->Delete().QueueDeleteSampler(nearestSampler_); } void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) { @@ -170,11 +128,6 @@ void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, boo } } -void FramebufferManagerVulkan::Bind2DShader() { - VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS); - cur2DPipeline_ = vulkan2D_->GetPipeline(rp, vsBasicTex_, fsBasicTex_); -} - void FramebufferManagerVulkan::BeginFrameVulkan() { BeginFrame(); } diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h index ad2f1df879..af3d9f2ef7 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -53,9 +53,6 @@ public: // do that. void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth); -protected: - void Bind2DShader() override; - private: void InitDeviceObjects(); void DestroyDeviceObjects(); @@ -70,18 +67,6 @@ private: VkPipelineCache pipelineCache2D_; - // Basic shaders - VkShaderModule fsBasicTex_ = VK_NULL_HANDLE; - VkShaderModule vsBasicTex_ = VK_NULL_HANDLE; - - VkShaderModule stencilVs_ = VK_NULL_HANDLE; - VkShaderModule stencilFs_ = VK_NULL_HANDLE; - - VkPipeline cur2DPipeline_ = VK_NULL_HANDLE; - - VkSampler linearSampler_; - VkSampler nearestSampler_; - // Simple 2D drawing engine. Vulkan2D *vulkan2D_; }; From f84d2e9ba7e7cd3f7089efbb6efdfd33b028a25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 17:26:07 +0200 Subject: [PATCH 26/35] Fixes, state invalidation --- GPU/Common/FramebufferManagerCommon.cpp | 10 ++++++---- GPU/Common/PresentationCommon.cpp | 4 +--- GPU/Common/StencilCommon.cpp | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index e0dca3b3cc..5e88a7ae03 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2390,6 +2390,7 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, } } + draw_->InvalidateCachedState(); textureCache_->ForgetLastTexture(); RebindFramebuffer("RebindFramebuffer - ReadFramebufferToMemory"); } @@ -2444,6 +2445,7 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo } void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { + draw_->InvalidateCachedState(); shaderManager_->DirtyLastShader(); if (currentRenderVfb_ && currentRenderVfb_->fbo) { draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); @@ -2599,8 +2601,8 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX useCopy = false; } - float srcXFactor = useBlit ? src->renderScaleFactor : 1.0f; - float srcYFactor = useBlit ? src->renderScaleFactor : 1.0f; + float srcXFactor = src->renderScaleFactor; + float srcYFactor = src->renderScaleFactor; const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; if (srcBpp != bpp && bpp != 0) { srcXFactor = (srcXFactor * bpp) / srcBpp; @@ -2610,8 +2612,8 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX int srcY1 = srcY * srcYFactor; int srcY2 = (srcY + h) * srcYFactor; - float dstXFactor = useBlit ? dst->renderScaleFactor : 1.0f; - float dstYFactor = useBlit ? dst->renderScaleFactor : 1.0f; + float dstXFactor = dst->renderScaleFactor; + float dstYFactor = dst->renderScaleFactor; const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; if (dstBpp != bpp && bpp != 0) { dstXFactor = (dstXFactor * bpp) / dstBpp; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index b34f8f4df8..ccfa4cdd88 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -795,13 +795,11 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u draw_->DrawIndexed(6, 0); } - draw_->BindIndexBuffer(nullptr, 0); - DoRelease(srcFramebuffer_); DoRelease(srcTexture_); // Unbinds all textures and samplers too, needed since sometimes a MakePixelTexture is deleted etc. - draw_->BindPipeline(nullptr); + draw_->InvalidateCachedState(); previousUniforms_ = uniforms; } diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 617880eb58..91583ea24f 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -322,8 +322,9 @@ bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilU draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST, "NotifyStencilUpload_Blit"); RebindFramebuffer("RebindFramebuffer - Stencil"); } - tex->Release(); + + draw_->InvalidateCachedState(); gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); return true; } From e28b45481b5b8b6597b112aca285a7b7d92c0f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 22:47:31 +0200 Subject: [PATCH 27/35] Delete more unused code --- GPU/Common/FramebufferManagerCommon.cpp | 1 - GPU/Common/FramebufferManagerCommon.h | 1 - GPU/D3D11/FramebufferManagerD3D11.cpp | 20 -------- GPU/D3D11/FramebufferManagerD3D11.h | 3 -- GPU/Directx9/FramebufferManagerDX9.cpp | 14 ------ GPU/Directx9/FramebufferManagerDX9.h | 2 - GPU/GLES/FramebufferManagerGLES.cpp | 64 ++++--------------------- GPU/GLES/FramebufferManagerGLES.h | 4 -- GPU/Vulkan/FramebufferManagerVulkan.cpp | 38 --------------- GPU/Vulkan/FramebufferManagerVulkan.h | 14 ------ GPU/Vulkan/GPU_Vulkan.cpp | 1 - 11 files changed, 8 insertions(+), 154 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 5e88a7ae03..fe23b16825 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1459,7 +1459,6 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, if (old.fbo) { INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->format)); if (vfb->fbo) { - // TODO: Swap the order of the below? That way we can avoid the needGLESRebinds_ check below I think. draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); if (!skipCopy) { // TODO: In this case, it'll nearly always be better to draw the old framebuffer to the new one than to do an actual blit. diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index f0b981ec1d..1cfe42c447 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -445,7 +445,6 @@ protected: int pixelHeight_; int bloomHack_ = 0; - bool needGLESRebinds_ = false; Draw::DataFormat preferredPixelsFormat_ = Draw::DataFormat::R8G8B8A8_UNORM; struct TempFBOInfo { diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 982e0f7eeb..9e59a07d8b 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -57,21 +57,6 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) vb.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; ASSERT_SUCCESS(device_->CreateBuffer(&vb, nullptr, &quadBuffer_)); - D3D11_TEXTURE2D_DESC desc{}; - desc.CPUAccessFlags = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.ArraySize = 1; - desc.SampleDesc.Count = 1; - desc.Width = 1; - desc.Height = 1; - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - desc.MipLevels = 1; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - ASSERT_SUCCESS(device_->CreateTexture2D(&desc, nullptr, &nullTexture_)); - ASSERT_SUCCESS(device_->CreateShaderResourceView(nullTexture_, nullptr, &nullTextureView_)); - uint32_t nullData[1]{}; - context_->UpdateSubresource(nullTexture_, 0, nullptr, nullData, 1, 0); - presentation_->SetLanguage(HLSL_D3D11); preferredPixelsFormat_ = Draw::DataFormat::B8G8R8A8_UNORM; } @@ -93,11 +78,6 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() { stencilUploadInputLayout_->Release(); if (stencilValueBuffer_) stencilValueBuffer_->Release(); - - if (nullTextureView_) - nullTextureView_->Release(); - if (nullTexture_) - nullTexture_->Release(); } void FramebufferManagerD3D11::SetTextureCache(TextureCacheD3D11 *tc) { diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index dc46158cc4..6dd9bbb3ea 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -62,7 +62,4 @@ private: ID3D11InputLayout *stencilUploadInputLayout_ = nullptr; ID3D11Buffer *stencilValueBuffer_ = nullptr; ID3D11DepthStencilState *stencilMaskStates_[256]{}; - - ID3D11Texture2D *nullTexture_ = nullptr; - ID3D11ShaderResourceView *nullTextureView_ = nullptr; }; diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index aec99b20c3..0bfe4c0ad1 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -53,18 +53,6 @@ namespace DX9 { device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE); deviceEx_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE_EX); - int usage = 0; - D3DPOOL pool = D3DPOOL_MANAGED; - if (deviceEx_) { - pool = D3DPOOL_DEFAULT; - usage = D3DUSAGE_DYNAMIC; - } - HRESULT hr = device_->CreateTexture(1, 1, 1, usage, D3DFMT_A8R8G8B8, pool, &nullTex_, nullptr); - D3DLOCKED_RECT rect; - nullTex_->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD); - memset(rect.pBits, 0, 4); - nullTex_->UnlockRect(0); - presentation_->SetLanguage(HLSL_D3D9); preferredPixelsFormat_ = Draw::DataFormat::B8G8R8A8_UNORM; } @@ -73,8 +61,6 @@ namespace DX9 { for (auto &it : offscreenSurfaces_) { it.second.surface->Release(); } - if (nullTex_) - nullTex_->Release(); } void FramebufferManagerDX9::SetTextureCache(TextureCacheDX9 *tc) { diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index c39b032fcd..fdb5cf1787 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -66,8 +66,6 @@ private: LPDIRECT3DDEVICE9 device_; LPDIRECT3DDEVICE9 deviceEx_; - LPDIRECT3DTEXTURE9 nullTex_ = nullptr; - struct OffscreenSurface { LPDIRECT3DSURFACE9 surface; int last_frame_used; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index d4ad9dadd4..74ce72e506 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -39,45 +39,16 @@ #include "GPU/GLES/DrawEngineGLES.h" #include "GPU/GLES/ShaderManagerGLES.h" -static const char tex_fs[] = R"( -#if __VERSION__ >= 130 -#define varying in -#define texture2D texture -#define gl_FragColor fragColor0 -out vec4 fragColor0; -#endif -#ifdef GL_ES -precision mediump float; -#endif -uniform sampler2D sampler0; -varying vec2 v_texcoord0; -void main() { - gl_FragColor = texture2D(sampler0, v_texcoord0); -} -)"; - -static const char basic_vs[] = R"( -#if __VERSION__ >= 130 -#define attribute in -#define varying out -#endif -attribute vec4 a_position; -attribute vec2 a_texcoord0; -varying vec2 v_texcoord0; -void main() { - v_texcoord0 = a_texcoord0; - gl_Position = a_position; -} -)"; - FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render) : FramebufferManagerCommon(draw), render_(render) { needBackBufferYSwap_ = true; - needGLESRebinds_ = true; presentation_->SetLanguage(draw_->GetShaderLanguageDesc().shaderLanguage); - CreateDeviceObjects(); +} + +FramebufferManagerGLES::~FramebufferManagerGLES() { + delete[] convBuf_; } void FramebufferManagerGLES::Init() { @@ -97,27 +68,6 @@ void FramebufferManagerGLES::SetDrawEngine(DrawEngineGLES *td) { drawEngine_ = td; } -void FramebufferManagerGLES::CreateDeviceObjects() { -} - -void FramebufferManagerGLES::DestroyDeviceObjects() { - if (stencilUploadPipeline_) { - stencilUploadPipeline_->Release(); - stencilUploadPipeline_ = nullptr; - } - - if (depthDownloadProgram_) { - render_->DeleteProgram(depthDownloadProgram_); - depthDownloadProgram_ = nullptr; - } -} - -FramebufferManagerGLES::~FramebufferManagerGLES() { - DestroyDeviceObjects(); - - delete [] convBuf_; -} - void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) { _assert_msg_(nvfb->fbo, "Expecting a valid nvfb in UpdateDownloadTempBuffer"); @@ -135,13 +85,15 @@ void FramebufferManagerGLES::EndFrame() { void FramebufferManagerGLES::DeviceLost() { FramebufferManagerCommon::DeviceLost(); - DestroyDeviceObjects(); + if (depthDownloadProgram_) { + render_->DeleteProgram(depthDownloadProgram_); + depthDownloadProgram_ = nullptr; + } } void FramebufferManagerGLES::DeviceRestore(Draw::DrawContext *draw) { FramebufferManagerCommon::DeviceRestore(draw); render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - CreateDeviceObjects(); } void FramebufferManagerGLES::Resized() { diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index adbd1b8ddf..20ddd1eab8 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -53,9 +53,6 @@ protected: void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; private: - void CreateDeviceObjects(); - void DestroyDeviceObjects(); - void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); GLRenderManager *render_; @@ -70,5 +67,4 @@ private: int u_depthDownloadTo8 = -1; DrawEngineGLES *drawEngineGL_ = nullptr; - }; diff --git a/GPU/Vulkan/FramebufferManagerVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp index 25107040c2..b3a63848e3 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.cpp +++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp @@ -49,38 +49,9 @@ using namespace PPSSPP_VK; -static const char tex_fs[] = R"(#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable -layout (binding = 0) uniform sampler2D sampler0; -layout (location = 0) in vec2 v_texcoord0; -layout (location = 0) out vec4 fragColor; -void main() { - fragColor = texture(sampler0, v_texcoord0); -} -)"; - -static const char tex_vs[] = R"(#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable -layout (location = 0) in vec3 a_position; -layout (location = 1) in vec2 a_texcoord0; -layout (location = 0) out vec2 v_texcoord0; -out gl_PerVertex { vec4 gl_Position; }; -void main() { - v_texcoord0 = a_texcoord0; - gl_Position = vec4(a_position, 1.0); -} -)"; - FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw) : FramebufferManagerCommon(draw) { presentation_->SetLanguage(GLSL_VULKAN); - - InitDeviceObjects(); - - // After a blit we do need to rebind for the VulkanRenderManager to know what to do. - needGLESRebinds_ = true; } FramebufferManagerVulkan::~FramebufferManagerVulkan() { @@ -99,13 +70,6 @@ void FramebufferManagerVulkan::SetDrawEngine(DrawEngineVulkan *td) { drawEngine_ = td; } -void FramebufferManagerVulkan::InitDeviceObjects() { -} - -void FramebufferManagerVulkan::DestroyDeviceObjects() { - -} - void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) { int mask = 0; // The Clear detection takes care of doing a regular draw instead if separate masking @@ -136,11 +100,9 @@ void FramebufferManagerVulkan::EndFrame() { } void FramebufferManagerVulkan::DeviceLost() { - DestroyDeviceObjects(); FramebufferManagerCommon::DeviceLost(); } void FramebufferManagerVulkan::DeviceRestore(Draw::DrawContext *draw) { FramebufferManagerCommon::DeviceRestore(draw); - InitDeviceObjects(); } diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h index af3d9f2ef7..7974aa6f5b 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -41,7 +41,6 @@ public: void SetShaderManager(ShaderManagerVulkan *sm); void SetDrawEngine(DrawEngineVulkan *td); void SetVulkan2D(Vulkan2D *vk2d) { vulkan2D_ = vk2d; } - void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } void BeginFrameVulkan(); // there's a BeginFrame in the base class, which this calls void EndFrame(); @@ -54,19 +53,6 @@ public: void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth); private: - void InitDeviceObjects(); - void DestroyDeviceObjects(); - - // Used to keep track of command buffers here but have moved all that into Thin3D. - - VulkanPushBuffer *push_; - - enum { - MAX_COMMAND_BUFFERS = 32, - }; - - VkPipelineCache pipelineCache2D_; - // Simple 2D drawing engine. Vulkan2D *vulkan2D_; }; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 8b6b980f5e..2c5a50aebc 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -327,7 +327,6 @@ void GPU_Vulkan::BeginHostFrame() { frame.push_->Begin(vulkan); framebufferManagerVulkan_->BeginFrameVulkan(); - framebufferManagerVulkan_->SetPushBuffer(frameData_[curFrame].push_); depalShaderCache_.SetPushBuffer(frameData_[curFrame].push_); textureCacheVulkan_->SetPushBuffer(frameData_[curFrame].push_); From e7e1bb60797068f62aeb0d5bfe4f226ea6f7ccb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 4 Aug 2022 10:44:12 +0200 Subject: [PATCH 28/35] UWP: Fix missing font file causing missing text fields. Fixes #15771 --- Common/UI/View.cpp | 2 +- UWP/UWP.vcxproj | 11 +++++++++-- UWP/UWP.vcxproj.filters | 15 ++++++++++----- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index c8f74ee1f1..72d3443ab0 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -1046,7 +1046,7 @@ void TextEdit::Draw(UIContext &dc) { } void TextEdit::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.size() ? text_.c_str() : "Wj", &w, &h, align_); + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, !text_.empty() ? text_.c_str() : "Wj", &w, &h, align_); w += 2; h += 2; } diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj index 767f2573fa..6426e6309b 100644 --- a/UWP/UWP.vcxproj +++ b/UWP/UWP.vcxproj @@ -184,14 +184,14 @@ - PPSSPP_UWP_TemporaryKey.pfx True False Never - b5e422213fb26042db3327f1102c4f9b86c27b1c + 169879A9D7A20F22B0DD435921035E3E6D5996A4 False 1 OnApplicationRun + True @@ -596,6 +596,13 @@ true Document + + true + Document + + + true + true diff --git a/UWP/UWP.vcxproj.filters b/UWP/UWP.vcxproj.filters index 4fcd4bd2ee..209fd4951f 100644 --- a/UWP/UWP.vcxproj.filters +++ b/UWP/UWP.vcxproj.filters @@ -88,9 +88,6 @@ Content - - Content - Content @@ -103,12 +100,17 @@ Assets + + Assets + + + Content + - Content @@ -365,6 +367,9 @@ Content\themes + + Content + @@ -376,4 +381,4 @@ Content - \ No newline at end of file + From bf98466a7809356c108d2f6f1645e64ca7fcd02e Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Mon, 28 Feb 2022 16:58:51 +0700 Subject: [PATCH 29/35] Added a FunctionWrapper used by sceNpService --- Core/HLE/FunctionWrappers.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 9feb73cd04..d745818338 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -765,6 +765,11 @@ template void WrapU_UUUUUUU() { RETURN(retval); } +template void WrapI_IUUUUUU() { + int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); + RETURN(retval); +} + template void WrapI_UIUU() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); RETURN(retval); From 54300eb017325f7806c98b5a9680b4d446581e0b Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Mon, 28 Feb 2022 16:20:03 +0700 Subject: [PATCH 30/35] Updated NP Library PS: Some of registered modules should probably moved to a separate files (ie. sceNp2.cpp). --- Core/HLE/sceNp.cpp | 886 +++++++++++++++++++++++++++++++++++++++++---- Core/HLE/sceNp.h | 432 +++++++++++++++++++++- 2 files changed, 1225 insertions(+), 93 deletions(-) diff --git a/Core/HLE/sceNp.cpp b/Core/HLE/sceNp.cpp index 3bd9d228b0..fd6eb1563c 100644 --- a/Core/HLE/sceNp.cpp +++ b/Core/HLE/sceNp.cpp @@ -26,25 +26,39 @@ #include #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" - #include "Core/HLE/sceNp.h" -#include bool npAuthInited = false; +int npSigninState = NP_SIGNIN_STATUS_NONE; SceNpAuthMemoryStat npAuthMemStat = {}; -std::string serviceId = ""; +SceNpAuthMemoryStat npMatching2MemStat = {}; +PSPTimeval npSigninTimestamp{}; -int parentalControl = PARENTAL_CONTROL_ENABLED; -int userAge = 24; // faking user Age to 24 yo -int chatRestriction = 0; // default/initial value on Patapon 3 is 1 (restricted boolean?) -std::string onlineId = "DummyOnlineId"; -std::string avatarUrl = "http://DummyAvatarUrl"; +// TODO: These should probably be grouped in a struct, since they're used to generate an auth ticket +int npParentalControl = PARENTAL_CONTROL_ENABLED; +int npUserAge = 24; // faking user Age to 24 yo +int npChatRestriction = 0; // default/initial value on Patapon 3 is 1 (restricted boolean?) +SceNpMyLanguages npMyLangList = { 1033, 2057, 1036 }; +char npCountryCode[3] = "fr"; // dummy data taken from https://www.psdevwiki.com/ps3/X-I-5-Ticket +char npRegionCode[3] = "c9"; // not sure what "c9" meant, since it was close to country code data, might be region-related data? +std::string npOnlineId = "DummyOnlineId"; // SceNpOnlineId struct? +std::string npServiceId = ""; // UNO game uses EP2006-NPEH00020_00 +std::string npAvatarUrl = "http://DummyAvatarUrl"; // SceNpAvatarUrl struct? + +bool npMatching2Inited = false; +SceNpCommunicationId npTitleId; std::recursive_mutex npAuthEvtMtx; std::deque npAuthEvents; std::map npAuthHandlers; +// TODO: Moves NpMatching2-related stuff to sceNp2.cpp +std::recursive_mutex npMatching2EvtMtx; +std::deque npMatching2Events; +std::map npMatching2Handlers; +//std::map npMatching2Contexts; + // Tickets data are in big-endian based on captured packets int writeTicketParam(u8* buffer, const u16_be type, const char* data = nullptr, const u16_be size = 0) { @@ -53,7 +67,8 @@ int writeTicketParam(u8* buffer, const u16_be type, const char* data = nullptr, u16_be sz = (data == nullptr)? static_cast(0): size; memcpy(buffer, &type, 2); memcpy(buffer + 2, &sz, 2); - if (sz>0) memcpy(buffer + 4, data, sz); + if (sz > 0 && data != nullptr) + memcpy(buffer + 4, data, sz); return sz + 4; } @@ -98,40 +113,163 @@ void notifyNpAuthHandlers(u32 id, u32 result, u32 argAddr) { npAuthEvents.push_back({ id, result, argAddr }); } +// serverId: 0 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d (ie. when already joined to a server?) +// unk1~unk5 usually 0, +// unk1: 1st 32-bit of LeaveRoom/etc's Arg2 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d/0x010e +// unk2: 2nd 32-bit of LeaveRoom/etc's Arg2 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d/0x010e +// unk5: 1 on 0x0002/0x0003/0x0005/0x0006/0x0007/0x0101/0x0102/0x0106 +// unk6 (new state?): 8-bit?(masked with 0xff) 0x01 on 0x0001, 0x03 on 0x0002, 0x04 on 0x0003, 0x05 on 0x0004, 0x06 on 0x0005, 0x07 on 0x0006, 0x08 on 0x0007, +// 0x09 on 0x0101, 0x0A on 0x0102, 0x0C on 0x0103, 0x0D on 0x0104, 0x0E on 0x0105, 0x0F on 0x0106, 0x10 on 0x0107, 0x11 on 0x0108, +// 0x12 on 0x0109, 0x13 on 0x010a, 0x14 on 0x010b, 0x15 on 0x010c, 0x16 on 0x010d, 0x17 on 0x010e, 0x18 on 0xa102 +void notifyNpMatching2Handlers(NpMatching2Args &args, u32 ctxId, u32 serverId, u32 cbFuncAddr, u32 cbArgAddr, u32 unk3, u32 unk4, u32 unk5, u8 unk6) { + std::lock_guard npMatching2Guard(npMatching2EvtMtx); + // TODO: separate/map each list per ctxId + npMatching2Events.push_back(args); +} + static int sceNpInit() { - ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); return 0; } static int sceNpTerm() { // No parameters - ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); return 0; } static int sceNpGetContentRatingFlag(u32 parentalControlAddr, u32 userAgeAddr) { - WARN_LOG(HLE, "UNTESTED %s(%08x, %08x)", __FUNCTION__, parentalControlAddr, userAgeAddr); + WARN_LOG(SCENET, "UNTESTED %s(%08x, %08x)", __FUNCTION__, parentalControlAddr, userAgeAddr); if (!Memory::IsValidAddress(parentalControlAddr) || !Memory::IsValidAddress(userAgeAddr)) - return hleLogError(HLE, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); - Memory::Write_U32(parentalControl, parentalControlAddr); - Memory::Write_U32(userAge, userAgeAddr); + INFO_LOG(SCENET, "%s - Parental Control: %d", __FUNCTION__, npParentalControl); + INFO_LOG(SCENET, "%s - User Age: %d", __FUNCTION__, npUserAge); + + Memory::Write_U32(npParentalControl, parentalControlAddr); + Memory::Write_U32(npUserAge, userAgeAddr); return 0; } static int sceNpGetChatRestrictionFlag(u32 flagAddr) { - WARN_LOG(HLE, "UNTESTED %s(%08x)", __FUNCTION__, flagAddr); + WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, flagAddr); if (!Memory::IsValidAddress(flagAddr)) - return hleLogError(HLE, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); - Memory::Write_U32(chatRestriction, flagAddr); + INFO_LOG(SCENET, "%s - Chat Restriction: %d", __FUNCTION__, npChatRestriction); + + Memory::Write_U32(npChatRestriction, flagAddr); + + return 0; +} + +static int sceNpGetOnlineId(u32 idPtr) +{ + WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, idPtr); + + if (!Memory::IsValidAddress(idPtr)) + return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + SceNpOnlineId dummyOnlineId{}; + truncate_cpy(dummyOnlineId.data, sizeof(dummyOnlineId.data), npOnlineId.c_str()); + + INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, dummyOnlineId.data); + + Memory::WriteStruct(idPtr, &dummyOnlineId); + + return 0; +} + +int NpGetNpId(SceNpId* npid) +{ + truncate_cpy(npid->handle.data, sizeof(npid->handle.data), npOnlineId.c_str()); + return 0; +} + +static int sceNpGetNpId(u32 idPtr) +{ + WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, idPtr); + + if (!Memory::IsValidAddress(idPtr)) + return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + SceNpId dummyNpId{}; + int retval = NpGetNpId(&dummyNpId); + if (retval < 0) + return hleLogError(SCENET, retval); + + INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, dummyNpId.handle.data); + std::string datahex; + DataToHexString(dummyNpId.opt, sizeof(dummyNpId.opt), &datahex); + INFO_LOG(SCENET, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); + + Memory::WriteStruct(idPtr, &dummyNpId); + + return 0; +} + +static int sceNpGetAccountRegion(u32 countryCodePtr, u32 regionCodePtr) +{ + WARN_LOG(SCENET, "UNTESTED %s(%08x, %08x)", __FUNCTION__, countryCodePtr, regionCodePtr); + + if (!Memory::IsValidAddress(countryCodePtr) || !Memory::IsValidAddress(regionCodePtr)) + return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + SceNpCountryCode dummyCountryCode{}; + memcpy(dummyCountryCode.data, npCountryCode, sizeof(dummyCountryCode.data)); + SceNpCountryCode dummyRegionCode{}; + memcpy(dummyRegionCode.data, npRegionCode, sizeof(dummyRegionCode.data)); + + INFO_LOG(SCENET, "%s - Country Code: %d", __FUNCTION__, dummyCountryCode.data); + INFO_LOG(SCENET, "%s - Region? Code: %d", __FUNCTION__, dummyRegionCode.data); + + Memory::WriteStruct(countryCodePtr, &dummyCountryCode); + Memory::WriteStruct(regionCodePtr, &dummyRegionCode); + + return 0; +} + +static int sceNpGetMyLanguages(u32 langListPtr) +{ + WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, langListPtr); + + if (!Memory::IsValidAddress(langListPtr)) + return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + INFO_LOG(SCENET, "%s - Language1 Code: %d", __FUNCTION__, npMyLangList.language1); + INFO_LOG(SCENET, "%s - Language2 Code: %d", __FUNCTION__, npMyLangList.language2); + INFO_LOG(SCENET, "%s - Language3 Code: %d", __FUNCTION__, npMyLangList.language3); + + Memory::WriteStruct(langListPtr, &npMyLangList); + + return 0; +} + +static int sceNpGetUserProfile(u32 profilePtr) +{ + WARN_LOG(SCENET, "UNTESTED %s(%08x)", __FUNCTION__, profilePtr); + + if (!Memory::IsValidAddress(profilePtr)) + return hleLogError(SCENET, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg"); + + SceNpUserInformation dummyProfile{}; + truncate_cpy(dummyProfile.userId.handle.data, sizeof(dummyProfile.userId.handle.data), npOnlineId.c_str()); + truncate_cpy(dummyProfile.icon.data, sizeof(dummyProfile.icon.data), npAvatarUrl.c_str()); + + INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, dummyProfile.userId.handle.data); + std::string datahex; + DataToHexString(dummyProfile.userId.opt, sizeof(dummyProfile.userId.opt), &datahex); + INFO_LOG(SCENET, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); + INFO_LOG(SCENET, "%s - Avatar URL: %s", __FUNCTION__, dummyProfile.icon.data); + + Memory::WriteStruct(profilePtr, &dummyProfile); return 0; } @@ -141,6 +279,11 @@ const HLEFunction sceNp[] = { {0X37E1E274, &WrapI_V, "sceNpTerm", 'i', "" }, {0XBB069A87, &WrapI_UU, "sceNpGetContentRatingFlag", 'i', "xx" }, {0X1D60AE4B, &WrapI_U, "sceNpGetChatRestrictionFlag", 'i', "x" }, + {0x4B5C71C8, &WrapI_U, "sceNpGetOnlineId", 'i', "x" }, + {0x633B5F71, &WrapI_U, "sceNpGetNpId", 'i', "x" }, + {0x7E0864DF, &WrapI_U, "sceNpGetUserProfile", 'i', "x" }, + {0xA0BE3C4B, &WrapI_UU, "sceNpGetAccountRegion", 'i', "xx" }, + {0xCDCC21D3, &WrapI_U, "sceNpGetMyLanguages", 'i', "x" }, }; void Register_sceNp() @@ -151,29 +294,29 @@ void Register_sceNp() static int sceNpAuthTerm() { // No parameters - ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); npAuthInited = false; return 0; } static int sceNpAuthInit(u32 poolSize, u32 stackSize, u32 threadPrio) { - ERROR_LOG(HLE, "UNIMPL %s(%d, %d, %d)", __FUNCTION__, poolSize, stackSize, threadPrio); - npAuthMemStat.npMemSize = poolSize; - npAuthMemStat.npMaxMemSize = poolSize / 2; // Dummy - npAuthMemStat.npFreeMemSize = poolSize - 16; // Dummy. + ERROR_LOG(SCENET, "UNIMPL %s(%d, %d, %d)", __FUNCTION__, poolSize, stackSize, threadPrio); + npAuthMemStat.npMemSize = poolSize - 0x20; + npAuthMemStat.npMaxMemSize = 0x4050; // Dummy maximum foot print + npAuthMemStat.npFreeMemSize = npAuthMemStat.npMemSize; npAuthEvents.clear(); npAuthInited = true; return 0; } -static int sceNpAuthGetMemoryStat(u32 memStatAddr) +int sceNpAuthGetMemoryStat(u32 memStatAddr) { - ERROR_LOG(HLE, "UNIMPL %s(%08x)", __FUNCTION__, memStatAddr); + ERROR_LOG(SCENET, "UNIMPL %s(%08x)", __FUNCTION__, memStatAddr); if (!Memory::IsValidAddress(memStatAddr)) - return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(SCENET, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); Memory::WriteStruct(memStatAddr, &npAuthMemStat); @@ -192,22 +335,23 @@ param seems to be a struct where offset: +20: 32-bit a pointer to a random data (4 to 8-bytes data max? both 2x 32-bit seems to be a valid pointer). optional handler args? return value >= 0 and <0 seems to be stored at a different location by the game (valid result vs error code?) */ -static int sceNpAuthCreateStartRequest(u32 paramAddr) +int sceNpAuthCreateStartRequest(u32 paramAddr) { - WARN_LOG(HLE, "UNTESTED %s(%08x) at %08x", __FUNCTION__, paramAddr, currentMIPS->pc); + WARN_LOG(SCENET, "UNTESTED %s(%08x) at %08x", __FUNCTION__, paramAddr, currentMIPS->pc); if (!Memory::IsValidAddress(paramAddr)) - return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(SCENET, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); SceNpAuthRequestParameter params = {}; int size = Memory::Read_U32(paramAddr); Memory::Memcpy(¶ms, paramAddr, size); - serviceId = Memory::GetCharPointer(params.serviceIdAddr); + npServiceId = Memory::GetCharPointer(params.serviceIdAddr); - INFO_LOG(HLE, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor); - INFO_LOG(HLE, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr)); - INFO_LOG(HLE, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr)); - INFO_LOG(HLE, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr)); + INFO_LOG(SCENET, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor); + INFO_LOG(SCENET, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr)); + INFO_LOG(SCENET, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr)); + INFO_LOG(SCENET, "%s - Consumed Count: %d", __FUNCTION__, params.consumedCount); + INFO_LOG(SCENET, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr)); u32 retval = 0; if (params.size >= 32 && params.ticketCbAddr != 0) { @@ -254,12 +398,12 @@ static int sceNpAuthCreateStartRequest(u32 paramAddr) // Used within callback of sceNpAuthCreateStartRequest (arg1 = callback's args[0], arg2 = output structPtr?, arg3 = callback's args[1]) // Is this using request id for Arg1 or cbId? // JPCSP is using length = 248 for dummy ticket -static int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) +int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) { - ERROR_LOG(HLE, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, requestId, bufferAddr, length, currentMIPS->pc); + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, requestId, bufferAddr, length, currentMIPS->pc); if (!Memory::IsValidAddress(bufferAddr)) - return hleLogError(HLE, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); + return hleLogError(SCENET, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg"); int result = length; Memory::Memset(bufferAddr, 0, length); @@ -269,35 +413,35 @@ static int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) ticket.header.size = 0xF0; // size excluding the header u8* buf = Memory::GetPointerWrite(bufferAddr + sizeof(ticket)); int ofs = 0; - ofs += writeTicketParam(buf, PARAM_TYPE_STRING_ASCII, "\x4c\x47\x56\x3b\x81\x39\x4a\x22\xd8\x6b\xc1\x57\x71\x6e\xfd\xb8\xab\x63\xcc\x51", 20); // 20 random letters, token key? + ofs += writeTicketParam(buf, PARAM_TYPE_STRING_ASCII, "\x4c\x47\x56\x3b\x81\x39\x4a\x22\xd8\x6b\xc1\x57\x71\x6e\xfd\xb8\xab\x63\xcc\x51", 20); // 20 random letters, token key or SceNpSignature? ofs += writeTicketU32Param(buf + ofs, PARAM_TYPE_INT, 0x0100); // a flags? - PSPTimeval tv; + PSPTimeval tv; //npSigninTimestamp __RtcTimeOfDay(&tv); u64 now = 1000ULL*tv.tv_sec + tv.tv_usec/1000ULL; // in milliseconds, since 1900? ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_DATE, now); ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_DATE, now + 10 * 60 * 1000); // now + 10 minutes, expired time? ofs += writeTicketU64Param(buf + ofs, PARAM_TYPE_LONG, 0x592e71c546e86859); // seems to be consistent, 8-bytes password hash may be? or related to entitlement? or console id? - ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, onlineId.c_str(), 32); // username - ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "fr\0\2", 4); // SceNpCountryCode ? ie. "fr" + 00 02 - ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, "c9", 4); // 2-char code? related to country/lang code? ie. "c9" + 00 00 - ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, serviceId.c_str(), 24); + ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, npOnlineId.c_str(), 32); // username + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, npCountryCode, 4); // SceNpCountryCode ? ie. "fr" + 00 02 + ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, npRegionCode, 4); // 2-char code? related to country/lang code? ie. "c9" + 00 00 + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, npServiceId.c_str(), 24); int status = 0; - if (parentalControl == PARENTAL_CONTROL_ENABLED) { + if (npParentalControl == PARENTAL_CONTROL_ENABLED) { status |= STATUS_ACCOUNT_PARENTAL_CONTROL_ENABLED; } - status |= (userAge & 0x7F) << 24; + status |= (npUserAge & 0x7F) << 24; ofs += writeTicketU32Param(buf + ofs, PARAM_TYPE_INT, status); ofs += writeTicketParam(buf + ofs, PARAM_TYPE_NULL); ofs += writeTicketParam(buf + ofs, PARAM_TYPE_NULL); ticket.section.type = SECTION_TYPE_BODY; ticket.section.size = ofs; Memory::WriteStruct(bufferAddr, &ticket); - SceNpTicketSection footer = { SECTION_TYPE_FOOTER, 32 }; // footer section? ie. 32-bytes on ver 2.1 containing 4-chars ASCII + 20-chars ASCII + SceNpTicketSection footer = { SECTION_TYPE_FOOTER, 32 }; // footer section? ie. 32-bytes on version 2.1 containing 4-chars ASCII + 20-chars ASCII Memory::WriteStruct(bufferAddr + sizeof(ticket) + ofs, &footer); ofs += sizeof(footer); ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x34\xcd\x3c\xa9", 4); - ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x3a\x4b\x42\x66\x92\xda\x6b\x7c\xb7\x4c\xe8\xd9\x4f\x2b\x77\x15\x91\xb8\xa4\xa9", 20); - u8 unknownBytes[36] = {}; + ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x3a\x4b\x42\x66\x92\xda\x6b\x7c\xb7\x4c\xe8\xd9\x4f\x2b\x77\x15\x91\xb8\xa4\xa9", 20); // 20 random letters, token key or SceNpSignature? + u8 unknownBytes[36] = {}; // includes Language list? Memory::WriteStruct(bufferAddr + sizeof(ticket) + ofs, unknownBytes); result = ticket.header.size + sizeof(ticket.header); // dummy ticket is 248 bytes @@ -307,28 +451,30 @@ static int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) // Used within callback of sceNpAuthCreateStartRequest (arg1 = structPtr?, arg2 = callback's args[1], arg3 = DLCcode? ie. "EP9000-UCES01421_00-DLL001", arg4 = Patapon 3 always set to 0?) // Patapon 3 will loop (for each DLC?) through an array of 4+4 bytes, ID addr (pchar) + result (int). Each loop calls this function using the same ticket addr but use different ID addr (arg3) and store the return value in result field (default/initial = -1) -static int sceNpAuthGetEntitlementById(u32 ticketBufferAddr, u32 ticketLength, u32 entitlementIdAddr, u32 arg4) +int sceNpAuthGetEntitlementById(u32 ticketBufferAddr, u32 ticketLength, u32 entitlementIdAddr, u32 arg4) { - ERROR_LOG(HLE, "UNIMPL %s(%08x, %d, %08x, %d)", __FUNCTION__, ticketBufferAddr, ticketLength, entitlementIdAddr, arg4); - INFO_LOG(HLE, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(entitlementIdAddr)); + ERROR_LOG(SCENET, "UNIMPL %s(%08x, %d, %08x, %d)", __FUNCTION__, ticketBufferAddr, ticketLength, entitlementIdAddr, arg4); + INFO_LOG(SCENET, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(entitlementIdAddr)); + // Do we return the entitlement through function result? or update the ticket content? or replace the arg3 data with SceNpEntitlement struct? return 1; // dummy value assuming it's a boolean/flag, since we don't know how to return the entitlement result yet } -static int sceNpAuthAbortRequest(int requestId) +int sceNpAuthAbortRequest(int requestId) { - WARN_LOG(HLE, "UNTESTED %s(%i)", __FUNCTION__, requestId); + WARN_LOG(SCENET, "UNTESTED %s(%i)", __FUNCTION__, requestId); // TODO: Disconnect HTTPS connection & cancel the callback event std::lock_guard npAuthGuard(npAuthEvtMtx); for (auto it = npAuthEvents.begin(); it != npAuthEvents.end(); ) { (it->data[0] == requestId) ? it = npAuthEvents.erase(it) : ++it; } + return 0; } -static int sceNpAuthDestroyRequest(int requestId) +int sceNpAuthDestroyRequest(int requestId) { - WARN_LOG(HLE, "UNTESTED %s(%i)", __FUNCTION__, requestId); + WARN_LOG(SCENET, "UNTESTED %s(%i)", __FUNCTION__, requestId); // Remove callback handler int handlerID = requestId - 1; if (npAuthHandlers.find(handlerID) != npAuthHandlers.end()) { @@ -338,20 +484,50 @@ static int sceNpAuthDestroyRequest(int requestId) else { ERROR_LOG(SCENET, "%s: Invalid request ID %d", __FUNCTION__, requestId); } + // Patapon 3 is checking for error code 0x80550402 return 0; } +int sceNpAuthGetTicketParam(u32 ticketBufPtr, int ticketLen, int paramNum, u32 bufferPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%08x, %0d, %d, %08x) at %08x", __FUNCTION__, ticketBufPtr, ticketLen, paramNum, bufferPtr, currentMIPS->pc); + const u32 PARAM_BUFFER_MAX_SIZE = 256; + Memory::Memset(bufferPtr, 0, PARAM_BUFFER_MAX_SIZE); // JPCSP: This clear is always done, even when an error is returned + if (paramNum < 0 || paramNum >= NUMBER_PARAMETERS) { + return SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT; + } + + SceNpTicket* ticket = (SceNpTicket*)Memory::GetPointer(ticketBufPtr); + u32 inbuf = ticketBufPtr; + inbuf += sizeof(ticket->header); + inbuf += ticket->section.size + sizeof(ticket->section); + u32 outbuf = bufferPtr; + for (int i = 0; i < paramNum; i++) { + SceNpTicketParamData* ticketParam = (SceNpTicketParamData*)Memory::GetPointer(inbuf); + u32 sz = (u32)sizeof(SceNpTicketParamData) + ticketParam->length; + Memory::Memcpy(outbuf, inbuf, sz); + DEBUG_LOG(SCENET, "%s - Param #%d: Type = %04x, Length = %u", __FUNCTION__, i, ticketParam->type, static_cast(ticketParam->length)); + outbuf += sz; + inbuf += sz; + if (outbuf - bufferPtr >= PARAM_BUFFER_MAX_SIZE || inbuf - ticketBufPtr >= (u32)ticketLen) + break; + } + + return 0; +} const HLEFunction sceNpAuth[] = { - {0X4EC1F667, &WrapI_V, "sceNpAuthTerm", 'i', "" }, - {0XA1DE86F8, &WrapI_UUU, "sceNpAuthInit", 'i', "xxx" }, - {0XF4531ADC, &WrapI_U, "sceNpAuthGetMemoryStat", 'i', "x" }, - {0XCD86A656, &WrapI_U, "sceNpAuthCreateStartRequest", 'i', "x" }, - {0X3F1C1F70, &WrapI_UUU, "sceNpAuthGetTicket", 'i', "xxx" }, - {0X6900F084, &WrapI_UUUU, "sceNpAuthGetEntitlementById", 'i', "xxxx" }, - {0XD99455DD, &WrapI_I, "sceNpAuthAbortRequest", 'i', "i" }, - {0X72BB0467, &WrapI_I, "sceNpAuthDestroyRequest", 'i', "i" }, + {0X4EC1F667, &WrapI_V, "sceNpAuthTerm", 'i', "" }, + {0XA1DE86F8, &WrapI_UUU, "sceNpAuthInit", 'i', "xxx" }, + {0XF4531ADC, &WrapI_U, "sceNpAuthGetMemoryStat", 'i', "x" }, + {0XCD86A656, &WrapI_U, "sceNpAuthCreateStartRequest", 'i', "x" }, + {0X3F1C1F70, &WrapI_UUU, "sceNpAuthGetTicket", 'i', "xxx" }, + {0X6900F084, &WrapI_UUUU, "sceNpAuthGetEntitlementById", 'i', "xxxx" }, + {0XD99455DD, &WrapI_I, "sceNpAuthAbortRequest", 'i', "i" }, + {0X72BB0467, &WrapI_I, "sceNpAuthDestroyRequest", 'i', "i" }, + {0x5A3CB57A, &WrapI_UIIU, "sceNpAuthGetTicketParam", 'i', "xiix" }, + {0x75FB0AE3, nullptr, "sceNpAuthGetEntitlementIdList", 'i', "" }, }; void Register_sceNpAuth() @@ -362,46 +538,90 @@ void Register_sceNpAuth() static int sceNpServiceTerm() { // No parameters - ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__); + ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); return 0; } static int sceNpServiceInit(u32 poolSize, u32 stackSize, u32 threadPrio) { - ERROR_LOG(HLE, "UNIMPL %s(%08x, %08x, %08x)", __FUNCTION__, poolSize, stackSize, threadPrio); + ERROR_LOG(SCENET, "UNIMPL %s(%08x, %08x, %08x)", __FUNCTION__, poolSize, stackSize, threadPrio); return 0; } +// FIXME: On Patapon 3 the Arg is pointing to a String, but based on RPCS3 the Arg is an Id integer ? static int sceNpLookupCreateTransactionCtx(u32 lookupTitleCtxIdAddr) { - ERROR_LOG(HLE, "UNIMPL %s(%08x)", __FUNCTION__, lookupTitleCtxIdAddr); + ERROR_LOG(SCENET, "UNIMPL %s(%08x)", __FUNCTION__, lookupTitleCtxIdAddr); INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, Memory::GetCharPointer(lookupTitleCtxIdAddr)); // Patapon 3 will only Destroy if returned Id > 0. Is 0 a valid id? return 1; // returning dummy transaction id } // transId: id returned from sceNpLookupCreateTransactionCtx -static int sceNpLookupDestroyTransactionCtx(u32 transId) +static int sceNpLookupDestroyTransactionCtx(s32 transId) { - ERROR_LOG(HLE, "UNIMPL %s(%d)", __FUNCTION__, transId); + ERROR_LOG(SCENET, "UNIMPL %s(%d)", __FUNCTION__, transId); return 0; } // transId: id returned from sceNpLookupCreateTransactionCtx // Patapon 3 always set Arg5 to 0 // Addr args have something to do with GameUpdate? -static int sceNpLookupTitleSmallStorage(u32 transId, u32 arg2Addr, u32 arg3, u32 arg4Addr, u32 arg5) +// FIXME: maxSize and contentLength are u64 based on https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp.cpp ? But on Patapon 3 optionAddr will be deadbeef if maxSize is u64 ? +static int sceNpLookupTitleSmallStorage(s32 transId, u32 dataAddr, u32 maxSize, u32 contentLengthAddr, u32 optionAddr) { - ERROR_LOG(HLE, "UNIMPL %s(%d, %08x, %08x, %08x, %08x)", __FUNCTION__, transId, arg2Addr, arg3, arg4Addr, arg5); + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %d, %08x[%d], %08x) at %08x", __FUNCTION__, transId, dataAddr, maxSize, contentLengthAddr, (Memory::IsValidAddress(contentLengthAddr)? Memory::Read_U32(contentLengthAddr): 0), optionAddr, currentMIPS->pc); + return 0; +} + +// On Resistance Retribution: +// unknownAddr pointing to a struct of: +// 32-bit pointer (ie. 08efc6c4)? or a timestamp combined with the next 32-bit value? +// 32-bit pointer (ie. 08f9d101)? but unaligned (the lowest byte seems to be intentionally set to 1)? so probably not a pointer, may be a timestamp combined with previous 32-bit value? +// 32-bit pointer? Seems to be pointing to dummy ticket data generated by sceNpAuthGetTicket +// 32-bit value (248) dummy ticket length from NpAuth Ticket? +// There could be more data in the struct? (at least 48-bytes?) +static int sceNpRosterCreateRequest(u32 unknownAddr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%08x) at %08x", __FUNCTION__, unknownAddr, currentMIPS->pc); + return 1; // returning dummy roster id +} + +// On Resistance Retribution: +// unknown1 set to 50 (max entries?), +// unknown2 set to 0, +// unknown3Addr pointing to unset buffer? (output entry data? usually located right after number of entries?), +// unknown4Addr pointing to 32-bit value set to 0 (output number of entries?), +// unknown5Addr pointing to zeroed buffer?, +// unknown6 set to 0 +static int sceNpRosterGetFriendListEntry(s32 rosterId, u32 unknown1, u32 unknown2, u32 unknown3Addr, u32 unknown4Addr, u32 unknown5Addr, u32 unknown6) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x, %08x, %08x, %08x) at %08x", __FUNCTION__, rosterId, unknown1, unknown2, unknown3Addr, unknown4Addr, unknown5Addr, unknown6, currentMIPS->pc); + return 0; +} + +static int sceNpRosterAbort(s32 rosterId) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, rosterId, currentMIPS->pc); + return 0; +} + +static int sceNpRosterDeleteRequest(s32 rosterId) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, rosterId, currentMIPS->pc); return 0; } const HLEFunction sceNpService[] = { - {0X00ACFAC3, &WrapI_V, "sceNpServiceTerm", 'i', "" }, - {0X0F8F5821, &WrapI_UUU, "sceNpServiceInit", 'i', "xxx" }, - {0X5494274B, &WrapI_U, "sceNpLookupCreateTransactionCtx", 'i', "x" }, - {0XA670D3A3, &WrapI_U, "sceNpLookupDestroyTransactionCtx", 'i', "x" }, - {0XC76F55ED, &WrapI_UUUUU, "sceNpLookupTitleSmallStorage", 'i', "xxxxx" }, + {0X00ACFAC3, &WrapI_V, "sceNpServiceTerm", 'i', "" }, + {0X0F8F5821, &WrapI_UUU, "sceNpServiceInit", 'i', "xxx" }, + {0X5494274B, &WrapI_U, "sceNpLookupCreateTransactionCtx", 'i', "x" }, + {0XA670D3A3, &WrapI_I, "sceNpLookupDestroyTransactionCtx", 'i', "i" }, + {0XC76F55ED, &WrapI_IUUUU, "sceNpLookupTitleSmallStorage", 'i', "ixxxx" }, + {0XBE22EEA3, &WrapI_U, "sceNpRosterCreateRequest", 'i', "x" }, + {0X4E851B10, &WrapI_IUUUUUU, "sceNpRosterGetFriendListEntry", 'i', "ixxxxxx"}, + {0X5F5E32AF, &WrapI_I, "sceNpRosterAbort", 'i', "i" }, + {0X66C64821, &WrapI_I, "sceNpRosterDeleteRequest", 'i', "i" }, }; void Register_sceNpService() @@ -409,6 +629,7 @@ void Register_sceNpService() RegisterModule("sceNpService", ARRAY_SIZE(sceNpService), sceNpService); } +// TODO: Moves NpCommerce2-related stuff to sceNpCommerce2.cpp const HLEFunction sceNpCommerce2[] = { {0X005B5F20, nullptr, "sceNpCommerce2GetProductInfoStart", '?', "" }, {0X0E9956E3, nullptr, "sceNpCommerce2Init", '?', "" }, @@ -432,3 +653,518 @@ void Register_sceNpCommerce2() { RegisterModule("sceNpCommerce2", ARRAY_SIZE(sceNpCommerce2), sceNpCommerce2); } + +static int sceNpMatching2Init(int poolSize, int threadPriority, int cpuAffinityMask, int threadStackSize) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %d, %d, %d) at %08x", __FUNCTION__, poolSize, threadPriority, cpuAffinityMask, threadStackSize, currentMIPS->pc); + //if (npMatching2Inited) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED); + + npMatching2MemStat.npMemSize = poolSize - 0x20; + npMatching2MemStat.npMaxMemSize = 0x4050; // Dummy maximum foot print + npMatching2MemStat.npFreeMemSize = npMatching2MemStat.npMemSize; + + npMatching2Handlers.clear(); + npMatching2Events.clear(); + npMatching2Inited = true; + return 0; +} + +static int sceNpMatching2Term() +{ + ERROR_LOG(SCENET, "UNIMPL %s() at %08x", __FUNCTION__, currentMIPS->pc); + npMatching2Inited = false; + npMatching2Handlers.clear(); + npMatching2Events.clear(); + + return 0; +} + +static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr, u32 ctxIdPtr, int unknown) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%08x[%s], %08x[%08x], %08x[%d], %d) at %08x", __FUNCTION__, communicationIdPtr, Memory::GetCharPointer(communicationIdPtr), passPhrasePtr, Memory::Read_U32(passPhrasePtr), ctxIdPtr, Memory::Read_U16(ctxIdPtr), unknown, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(communicationIdPtr) || !Memory::IsValidAddress(passPhrasePtr) || !Memory::IsValidAddress(ctxIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); + + // FIXME: It seems Context are mapped to TitleID? may return 0x80550C05 or 0x80550C06 when finding an existing context + SceNpCommunicationId* titleid = (SceNpCommunicationId*)Memory::GetCharPointer(communicationIdPtr); + memcpy(npTitleId.data, titleid->data, sizeof(npTitleId)); + + SceNpCommunicationPassphrase* passph = (SceNpCommunicationPassphrase*)Memory::GetCharPointer(passPhrasePtr); + + SceNpId npid{}; + int retval = NpGetNpId(&npid); + if (retval < 0) + return hleLogError(SCENET, retval); + + INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, titleid->data); + INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, npid.handle.data); + std::string datahex; + DataToHexString(npid.opt, sizeof(npid.opt), &datahex); + INFO_LOG(SCENET, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); + datahex.clear(); + DataToHexString(10, 0, passph->data, sizeof(passph->data), &datahex); + INFO_LOG(SCENET, "%s - Passphrase: \n%s", __FUNCTION__, datahex.c_str()); + + // TODO: Allocate & zeroed a memory of 68 bytes where npId (36 bytes) is copied to offset 8, offset 44 = 0x00026808, offset 48 = 0 + + // Returning dummy Id, a 16-bit variable according to JPCSP + // FIXME: It seems ctxId need to be in the range of 1 to 7 to be valid ? + Memory::Write_U16(1, ctxIdPtr); + return 0; +} + +static int sceNpMatching2ContextStart(int ctxId) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + //if (!npMatching2Ctx) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + + //if (npMatching2Ctx.started) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED); + + // TODO: use sceNpGetUserProfile and check server availability using sceNpService_76867C01 + //npMatching2Ctx.started = true; + Url url("http://static-resource.np.community.playstation.net/np/resource/psp-title/" + std::string(npTitleId.data) + "_00/matching/" + std::string(npTitleId.data) + "_00-matching.xml"); + http::Client client; + http::RequestProgress progress; + if (!client.Resolve(url.Host().c_str(), url.Port())) { + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP failed to resolve %s", url.Resource().c_str()); + } + + client.SetDataTimeout(20.0); + if (client.Connect()) { + char requestHeaders[4096]; + snprintf(requestHeaders, sizeof(requestHeaders), + "User-Agent: PS3Community-agent/1.0.0 libhttp/1.0.0\r\n"); + + DEBUG_LOG(SCENET, "GET URI: %s", url.ToString().c_str()); + http::RequestParams req(url.Resource(), "*/*"); + int err = client.SendRequest("GET", req, requestHeaders, &progress); + if (err < 0) { + client.Disconnect(); + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP GET Error = %d", err); + } + + net::Buffer readbuf; + std::vector responseHeaders; + int code = client.ReadResponseHeaders(&readbuf, responseHeaders, &progress); + if (code != 200) { + client.Disconnect(); + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP Error Code = %d", code); + } + + net::Buffer output; + int res = client.ReadResponseEntity(&readbuf, responseHeaders, &output, &progress); + if (res != 0) { + WARN_LOG(SCENET, "Unable to read HTTP response entity: %d", res); + } + client.Disconnect(); + + std::string entity; + size_t readBytes = output.size(); + output.Take(readBytes, &entity); + + // TODO: Use XML Parser to get the Tag and it's attributes instead of searching for keywords on the string + std::string text; + size_t ofs = entity.find("titleid="); + if (ofs == std::string::npos) + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "titleid not found"); + + ofs += 9; + size_t ofs2 = entity.find('"', ofs); + text = entity.substr(ofs, ofs2-ofs); + INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, text.c_str()); + + int i = 1; + while (true) { + ofs = entity.find("", ++ofs2); + if (ofs == std::string::npos) + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent host not found"); + + ofs2 = entity.find("pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + //if (!npMatching2Ctx) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + + //if (!npMatching2Ctx.started) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED); + + //TODO: Stop any in-progress HTTPClient communication used on sceNpMatching2ContextStart + //npMatching2Ctx.started = false; + + return 0; +} + +static int sceNpMatching2DestroyContext(int ctxId) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + //if (!npMatching2Ctx) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + + // Remove callback handler + int handlerID = ctxId - 1; + if (npMatching2Handlers.find(handlerID) != npMatching2Handlers.end()) { + npMatching2Handlers.erase(handlerID); + WARN_LOG(SCENET, "%s: Deleted handler %d", __FUNCTION__, handlerID); + } + else { + ERROR_LOG(SCENET, "%s: Invalid Context ID %d", __FUNCTION__, ctxId); + } + + return 0; +} + +static int sceNpMatching2GetMemoryStat(u32 memStatPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%08x) at %08x", __FUNCTION__, memStatPtr, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(memStatPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); + + Memory::WriteStruct(memStatPtr, &npMatching2MemStat); + + return 0; +} + +static int sceNpMatching2RegisterSignalingCallback(int ctxId, u32 callbackFunctionAddr, u32 callbackArgument) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x) at %08x", __FUNCTION__, ctxId, callbackFunctionAddr, callbackArgument, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (ctxId <= 0) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID); + + int id = ctxId - 1; + if (callbackFunctionAddr != 0) { + bool foundHandler = false; + + struct NpMatching2Handler handler; + memset(&handler, 0, sizeof(handler)); + + handler.entryPoint = callbackFunctionAddr; + handler.argument = callbackArgument; + + for (std::map::iterator it = npMatching2Handlers.begin(); it != npMatching2Handlers.end(); it++) { + if (it->second.entryPoint == handler.entryPoint) { + foundHandler = true; + id = it->first; + break; + } + } + + if (!foundHandler && Memory::IsValidAddress(handler.entryPoint)) { + npMatching2Handlers[id] = handler; + WARN_LOG(SCENET, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, id); + } + else { + ERROR_LOG(SCENET, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); + } + + //u32 dataLength = 4097; + //notifyNpMatching2Handlers(retval, dataLength, handler.argument); + + // callback struct have 57 * u32? where [0]=0, [40]=flags, [55]=callbackFunc, and [56]=callbackArgs? + //hleEnqueueCall(callbackFunctionAddr, 7, (u32*)Memory::GetPointer(callbackArgument), nullptr); // 7 args? since the callback handler is trying to use t2 register + } + return 0; +} + +static int sceNpMatching2GetServerIdListLocal(int ctxId, u32 serverIdsPtr, int maxServerIds) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, ctxId, serverIdsPtr, maxServerIds, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(serverIdsPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); + + // Returning dummy Id, a 16-bit variable according to JPCSP + for (int i = 0; i < maxServerIds; i++) + Memory::Write_U16(1234+i, serverIdsPtr+(i*2)); + + return maxServerIds; // dummy value +} + +// Unknown1 = optParam, unknown2 = assignedReqId according to https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.cpp ? +static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1Ptr, u32 unknown2Ptr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x[%d], %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, serverIdPtr, Memory::Read_U16(serverIdPtr), unknown1Ptr, unknown2Ptr, Memory::Read_U32(unknown2Ptr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(serverIdPtr) || !Memory::IsValidAddress(unknown2Ptr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + // Server ID is a 16-bit variable according to JPCSP + int serverId = Memory::Read_U16(serverIdPtr); + + if (serverId == 0) + return hleLogError(SCENET, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? + + // Output to unknown1(infoBuffer)? and unknown2(infoLength or flags)? + // Patapon 3 is using serverId at 09FFF2F4, unknown1 at 09FFF2E4, unknown2 at 09FFF2E0, which mean unknown1's can only fit upto 16-bytes + // Patapon 3 seems to be copying data from unknown1 with a fixed size of 20-bytes? + // input unknown1 struct: based on Fat Princess (US) + // 0000 32-bit function address (callback?) 0x08A08B40 + // 0004 32-bit pointer to a struct? (callback args?) 0x09888158 (contains 32-bit (-1) + 32-bit (1) + 16-bit ctxId(0001) + 32bit 0x06913801? + 16-bit serverId(1234), so on), probably only 2x 32-bit struct? + // 0008 32-bit set to 0 + // 000a 16-bit set to 0 + // + u32 cbFunc = Memory::Read_U32(unknown1Ptr); + u32 cbArg = Memory::Read_U32(unknown1Ptr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // The cbFunc seems to be storing s0~s4(s0 pointing to 0x0996DD58 containing data similar to 0x09888158 above on the 1st 2x 32-bit data, s1 seems to be ctxId, s2~s4=0xdeadbeef) into stack and use a0~t1 (6 args?): + // Arg1(a0) & Arg3(a2) are being masked with 0xffff (16-bit id?) + // This callback tried to load data from address 0x08BD4860+8 (not part of arg? which being set using content of unknown2 not long after returning from sceNpMatching2GetServerInfo, so we may need to give some delay before calling this callback) + // and comparing it with Arg2(a1), repeated by increasing the address 0x08BD4860 by 288 bytes on each loop for 64 times or until it found a matching one. + // When a match is found the callback will process the address further, otherwise exit the callback. + // Matching address struct: (zeroed before calling sceNpMatching2GetServerInfo? and set after returning from sceNpMatching2GetServerInfo?) + // 0000 32-bit func address (another callback?) 0x08A07EF4 + // 0008 32-bit value from unknown2 content, being set not long after returning from sceNpMatching2GetServerInfo + // 000c 32-bit unknown + // 0010 8-bit status to indicate not updated from callback yet? initially 0, set to 1 not long after returning from sceNpMatching2GetServerInfo (along with unknown2 content) + // + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + args.data[0] = PSP_NP_MATCHING2_EVENT_0001; + args.data[1] = PSP_NP_MATCHING2_STATE_1001; // or size of data? + args.data[2] = serverIdPtr; // serverId or was it pointing to optional data at last arg (ie. args[10] where serverId is stored)? + args.data[3] = unknown1Ptr; + //args.data[4] = a boolean(0/1) related to a u8 value from the struct at args[9] (value XOR 0x04 == 0) + args.data[5] = unknown2Ptr; + args.data[6] = 0; + //args.data[8] = 0 or a pointer to a struct related to context? + //args.data[9] = 0 or a pointer to a struct related to context and matched serverId? + //args.data[10] = serverId; + + notifyNpMatching2Handlers(args, ctxId, serverId, 0, 0, 0, 0, 0, 1); + + Memory::Write_U32(args.data[1], unknown2Ptr); // server status or flags? + } + + // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? + return 0; +} + +static int sceNpMatching2LeaveRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + u32 cbFunc = Memory::Read_U32(reqParamPtr); + u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + args.data[0] = PSP_NP_MATCHING2_EVENT_0103; + args.data[1] = PSP_NP_MATCHING2_STATE_3202; + //args.data[2] = pointer to arg[8], where the 1st 20 bytes copied from (reqParamPtr+0x08), the rest of the struct are zeroed + args.data[3] = optParamPtr; + args.data[4] = 0; + args.data[5] = assignedReqIdPtr; + args.data[6] = 0; + //args.data[8] = an initially zeroed struct of 536 bytes where the 1st 20 bytes were taken from reqParam offset 0x08 + + notifyNpMatching2Handlers(args, ctxId, 0, cbFunc, cbArg, 0, 0, 0, 0x0c); + + Memory::Write_U32(args.data[1], assignedReqIdPtr); + } + + // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? + return 0; +} + +static int sceNpMatching2JoinRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 unknown1, u32 unknown2, u32 assignedReqIdPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + // Server ID is a 16-bit variable according to JPCSP + int serverId = Memory::Read_U16(reqParamPtr + 0x06); + + if (serverId == 0) + return hleLogError(SCENET, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? + + u32 cbFunc = Memory::Read_U32(reqParamPtr); + u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + args.data[0] = PSP_NP_MATCHING2_EVENT_0102; + args.data[1] = PSP_NP_MATCHING2_STATE_1209; + //args.data[2] = pointer to arg[8] (optional data?) + args.data[3] = optParamPtr; + args.data[4] = 0; + args.data[5] = assignedReqIdPtr; + args.data[6] = 0; + // Followed by optional data? + args.data[8] = reqParamPtr; // an initially zeroed struct of 1224 bytes, where the 1st 32bit is set to reqParamPtr + args.data[9] = unknown1; + args.data[10] = unknown2; + + notifyNpMatching2Handlers(args, ctxId, serverId, 0, 0, 0, 0, 1, 0x0a); + + Memory::Write_U32(args.data[1], assignedReqIdPtr); + } + + // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? + return 0; +} + +static int sceNpMatching2SearchRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + u32 cbFunc = Memory::Read_U32(reqParamPtr); + u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + // TODO: Set the correct callback args + + Memory::Write_U32(args.data[1], assignedReqIdPtr); // server status or flags? + } + + return 0; +} + +static int sceNpMatching2SendRoomChatMessage(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + u32 cbFunc = Memory::Read_U32(reqParamPtr); + u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + args.data[0] = PSP_NP_MATCHING2_EVENT_0107; + args.data[1] = PSP_NP_MATCHING2_STATE_3208; + //args.data[2] = pointer to arg[8] + args.data[3] = optParamPtr; + args.data[4] = 0; + args.data[5] = assignedReqIdPtr; + args.data[6] = 0; + //args.data[8] = reqParamPtr; + + notifyNpMatching2Handlers(args, ctxId, 0, cbFunc, cbArg, 0, 0, 0, 0x10); + + Memory::Write_U32(args.data[1], assignedReqIdPtr); // server status or flags? + } + + // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? + return 0; +} + +const HLEFunction sceNpMatching2[] = { + {0x2E61F6E1, &WrapI_IIII, "sceNpMatching2Init", 'i', "iiii" }, + {0x8BF37D8C, &WrapI_V, "sceNpMatching2Term", 'i', "" }, + {0x5030CC53, &WrapI_UUUI, "sceNpMatching2CreateContext", 'i', "xxxi" }, + {0x190FF903, &WrapI_I, "sceNpMatching2ContextStart", 'i', "i" }, + {0x2B3892FC, &WrapI_I, "sceNpMatching2ContextStop", 'i', "i" }, + {0x3DE70241, &WrapI_I, "sceNpMatching2DestroyContext", 'i', "i" }, + {0x22F38DAF, &WrapI_U, "sceNpMatching2GetMemoryStat", 'i', "x" }, + {0xA3C298D1, &WrapI_IUU, "sceNpMatching2RegisterSignalingCallback", 'i', "ixx" }, + {0xF47342FC, &WrapI_IUI, "sceNpMatching2GetServerIdListLocal", 'i', "ixi" }, + {0x4EE3A8EC, &WrapI_IUUU, "sceNpMatching2GetServerInfo", 'i', "ixxx" }, + {0xC870535A, &WrapI_IUUU, "sceNpMatching2LeaveRoom", 'i', "ixxx" }, + {0xAAD0946A, &WrapI_IUUUUU, "sceNpMatching2JoinRoom", 'i', "ixxxxx" }, + {0x81C13E6D, &WrapI_IUUU, "sceNpMatching2SearchRoom", 'i', "ixxx" }, + {0x55F7837F, &WrapI_IUUU, "sceNpMatching2SendRoomChatMessage", 'i', "ixxx" }, +}; + +void Register_sceNpMatching2() +{ + RegisterModule("sceNpMatching2", ARRAY_SIZE(sceNpMatching2), sceNpMatching2); +} diff --git a/Core/HLE/sceNp.h b/Core/HLE/sceNp.h index 3c117b33c7..0be9f0ca54 100644 --- a/Core/HLE/sceNp.h +++ b/Core/HLE/sceNp.h @@ -17,9 +17,13 @@ #pragma once -#ifdef _MSC_VER +#include +#include "Common/Net/HTTPClient.h" +#include "Common/Net/Resolve.h" +#include "Common/Net/URL.h" + + #pragma pack(push,1) -#endif // Based on https://playstationdev.wiki/psvitadevwiki/index.php?title=Error_Codes #define SCE_NP_ERROR_ALREADY_INITIALIZED 0x80550001 @@ -47,6 +51,261 @@ #define SCE_NP_AUTH_ERROR_SERVICE_END 0x80550400 #define SCE_NP_AUTH_ERROR_SERVICE_DOWN 0x80550401 #define SCE_NP_AUTH_ERROR_SERVICE_BUSY 0x80550402 +#define SCE_NP_AUTH_ERROR_SERVER_MAINTENANCE 0x80550403 +#define SCE_NP_AUTH_ERROR_UNKNOWN 0x80550480 + +#define SCE_NP_MANAGER_ERROR_ALREADY_INITIALIZED 0x80550501 +#define SCE_NP_MANAGER_ERROR_NOT_INITIALIZED 0x80550502 +#define SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT 0x80550503 +#define SCE_NP_MANAGER_ERROR_OUT_OF_MEMORY 0x80550504 +#define SCE_NP_MANAGER_ERROR_INVALID_TICKET_SIZE 0x80550505 +#define SCE_NP_MANAGER_ERROR_INVALID_STATE 0x80550506 +#define SCE_NP_MANAGER_ERROR_ABORTED 0x80550507 +#define SCE_NP_MANAGER_ERROR_VARIANT_ACCOUNT_ID 0x80550508 +#define SCE_NP_MANAGER_ERROR_ID_NOT_AVAIL 0x80550509 +#define SCE_NP_MANAGER_ERROR_SIGNOUT 0x8055050a +#define SCE_NP_MANAGER_ERROR_NOT_SIGNIN 0x8055050b + +#define SCE_NP_UTIL_ERROR_INVALID_ARGUMENT 0x80550601 +#define SCE_NP_UTIL_ERROR_INSUFFICIENT 0x80550602 +#define SCE_NP_UTIL_ERROR_PARSER_FAILED 0x80550603 +#define SCE_NP_UTIL_ERROR_INVALID_PROTOCOL_ID 0x80550604 +#define SCE_NP_UTIL_ERROR_INVALID_NP_ID 0x80550605 +#define SCE_NP_UTIL_ERROR_INVALID_NP_ENV 0x80550606 +#define SCE_NP_UTIL_ERROR_INVALID_NPCOMMID 0x80550607 +#define SCE_NP_UTIL_ERROR_INVALID_CHARACTER 0x80550608 +#define SCE_NP_UTIL_ERROR_NOT_MATCH 0x80550609 +#define SCE_NP_UTIL_ERROR_INVALID_TITLEID 0x8055060a +#define SCE_NP_UTIL_ERROR_INVALID_ESCAPE_STRING 0x8055060c +#define SCE_NP_UTIL_ERROR_UNKNOWN_TYPE 0x8055060d +#define SCE_NP_UTIL_ERROR_UNKNOWN 0x8055060e + +#define SCE_NP_COMMUNITY_ERROR_ALREADY_INITIALIZED 0x80550701 +#define SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED 0x80550702 +#define SCE_NP_COMMUNITY_ERROR_OUT_OF_MEMORY 0x80550703 +#define SCE_NP_COMMUNITY_ERROR_INVALID_ARGUMENT 0x80550704 +#define SCE_NP_COMMUNITY_ERROR_NO_LOGIN 0x80550705 +#define SCE_NP_COMMUNITY_ERROR_TOO_MANY_OBJECTS 0x80550706 +#define SCE_NP_COMMUNITY_ERROR_ABORTED 0x80550707 +#define SCE_NP_COMMUNITY_ERROR_BAD_RESPONSE 0x80550708 +#define SCE_NP_COMMUNITY_ERROR_BODY_TOO_LARGE 0x80550709 +#define SCE_NP_COMMUNITY_ERROR_HTTP_SERVER 0x8055070a +#define SCE_NP_COMMUNITY_ERROR_INVALID_SIGNATURE 0x8055070b +#define SCE_NP_COMMUNITY_ERROR_INSUFFICIENT_ARGUMENT 0x8055070c +#define SCE_NP_COMMUNITY_ERROR_UNKNOWN_TYPE 0x8055070d +#define SCE_NP_COMMUNITY_ERROR_INVALID_ID 0x8055070e +#define SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID 0x8055070f +#define SCE_NP_COMMUNITY_ERROR_CONNECTION_HANDLE_ALREADY_EXISTS 0x80550710 +#define SCE_NP_COMMUNITY_ERROR_INVALID_TYPE 0x80550711 +#define SCE_NP_COMMUNITY_ERROR_TRANSACTION_ALREADY_END 0x80550712 +#define SCE_NP_COMMUNITY_ERROR_INVALID_PARTITION 0x80550713 +#define SCE_NP_COMMUNITY_ERROR_INVALID_ALIGNMENT 0x80550714 +#define SCE_NP_COMMUNITY_ERROR_CLIENT_HANDLE_ALREADY_EXISTS 0x80550715 +#define SCE_NP_COMMUNITY_ERROR_NO_RESOURCE 0x80550716 + +#define SCE_NP_COMMUNITY_SERVER_ERROR_BAD_REQUEST 0x80550801 +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_TICKET 0x80550802 +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_SIGNATURE 0x80550803 +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_NPID 0x80550805 +#define SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN 0x80550806 +#define SCE_NP_COMMUNITY_SERVER_ERROR_INTERNAL_SERVER_ERROR 0x80550807 +#define SCE_NP_COMMUNITY_SERVER_ERROR_VERSION_NOT_SUPPORTED 0x80550808 +#define SCE_NP_COMMUNITY_SERVER_ERROR_SERVICE_UNAVAILABLE 0x80550809 +#define SCE_NP_COMMUNITY_SERVER_ERROR_PLAYER_BANNED 0x8055080a +#define SCE_NP_COMMUNITY_SERVER_ERROR_CENSORED 0x8055080b +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_RECORD_FORBIDDEN 0x8055080c +#define SCE_NP_COMMUNITY_SERVER_ERROR_USER_PROFILE_NOT_FOUND 0x8055080d +#define SCE_NP_COMMUNITY_SERVER_ERROR_UPLOADER_DATA_NOT_FOUND 0x8055080e +#define SCE_NP_COMMUNITY_SERVER_ERROR_QUOTA_MASTER_NOT_FOUND 0x8055080f +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_TITLE_NOT_FOUND 0x80550810 +#define SCE_NP_COMMUNITY_SERVER_ERROR_BLACKLISTED_USER_ID 0x80550811 +#define SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND 0x80550812 +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_STORE_NOT_FOUND 0x80550814 +#define SCE_NP_COMMUNITY_SERVER_ERROR_NOT_BEST_SCORE 0x80550815 +#define SCE_NP_COMMUNITY_SERVER_ERROR_LATEST_UPDATE_NOT_FOUND 0x80550816 +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_BOARD_MASTER_NOT_FOUND 0x80550817 +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_GAME_DATA_MASTER_NOT_FOUND 0x80550818 +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_ANTICHEAT_DATA 0x80550819 +#define SCE_NP_COMMUNITY_SERVER_ERROR_TOO_LARGE_DATA 0x8055081a +#define SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_USER_NPID 0x8055081b +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_ENVIRONMENT 0x8055081d +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_ONLINE_NAME_CHARACTER 0x8055081f +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_ONLINE_NAME_LENGTH 0x80550820 +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_ABOUT_ME_CHARACTER 0x80550821 +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_ABOUT_ME_LENGTH 0x80550822 +#define SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_SCORE 0x80550823 +#define SCE_NP_COMMUNITY_SERVER_ERROR_OVER_THE_RANKING_LIMIT 0x80550824 +#define SCE_NP_COMMUNITY_SERVER_ERROR_FAIL_TO_CREATE_SIGNATURE 0x80550826 +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_MASTER_INFO_NOT_FOUND 0x80550827 +#define SCE_NP_COMMUNITY_SERVER_ERROR_OVER_THE_GAME_DATA_LIMIT 0x80550828 +#define SCE_NP_COMMUNITY_SERVER_ERROR_SELF_DATA_NOT_FOUND 0x8055082a +#define SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED 0x8055082b +#define SCE_NP_COMMUNITY_SERVER_ERROR_GAME_DATA_ALREADY_EXISTS 0x8055082c +#define SCE_NP_COMMUNITY_SERVER_ERROR_MATCHING_BEFORE_SERVICE 0x805508a0 +#define SCE_NP_COMMUNITY_SERVER_ERROR_MATCHING_END_OF_SERVICE 0x805508a1 +#define SCE_NP_COMMUNITY_SERVER_ERROR_MATCHING_MAINTENANCE 0x805508a2 +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_BEFORE_SERVICE 0x805508a3 +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_END_OF_SERVICE 0x805508a4 +#define SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_MAINTENANCE 0x805508a5 +#define SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE 0x805508a6 +#define SCE_NP_COMMUNITY_SERVER_ERROR_TITLE_USER_STORAGE_BEFORE_SERVICE 0x805508aa +#define SCE_NP_COMMUNITY_SERVER_ERROR_TITLE_USER_STORAGE_END_OF_SERVICE 0x805508ab +#define SCE_NP_COMMUNITY_SERVER_ERROR_TITLE_USER_STORAGE_MAINTENANCE 0x805508ac +#define SCE_NP_COMMUNITY_SERVER_ERROR_FSR_BEFORE_SERVICE 0x805508ad +#define SCE_NP_COMMUNITY_SERVER_ERROR_FSR_END_OF_SERVICE 0x805508ae +#define SCE_NP_COMMUNITY_SERVER_ERROR_FSR_MAINTENANCE 0x805508af +#define SCE_NP_COMMUNITY_SERVER_ERROR_UBS_BEFORE_SERVICE 0x805508b1 +#define SCE_NP_COMMUNITY_SERVER_ERROR_UBS_END_OF_SERVICE 0x805508b2 +#define SCE_NP_COMMUNITY_SERVER_ERROR_UBS_MAINTENANCE 0x805508b3 +#define SCE_NP_COMMUNITY_SERVER_ERROR_UNSPECIFIED 0x805508ff + +// TODO: Moves NpMatching2-related stuff to sceNp2.h +// Based on https://gist.githubusercontent.com/raw/4140449/PS%20Vita (Might be slightly different with PSP?) +#define SCE_NP_MATCHING2_ERROR_OUT_OF_MEMORY 0x80550c01 +#define SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED 0x80550c02 +#define SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED 0x80550c03 +#define SCE_NP_MATCHING2_ERROR_CONTEXT_MAX 0x80550c04 // might be "Invalid Argument" on PSP? +#define SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_EXISTS 0x80550c05 // might be "Context Max/Context Id higher than 7" on PSP? +#define SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND 0x80550c06 +#define SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED 0x80550c07 +#define SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED 0x80550c08 +#define SCE_NP_MATCHING2_ERROR_SERVER_NOT_FOUND 0x80550c09 +#define SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT 0x80550c0a +#define SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID 0x80550c0b +#define SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID 0x80550c0c +#define SCE_NP_MATCHING2_ERROR_INVALID_LOBBY_ID 0x80550c0e +#define SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID 0x80550c0f +#define SCE_NP_MATCHING2_ERROR_INVALID_MEMBER_ID 0x80550c10 +#define SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_ID 0x80550c11 +#define SCE_NP_MATCHING2_ERROR_INVALID_CASTTYPE 0x80550c12 +#define SCE_NP_MATCHING2_ERROR_INVALID_SORT_METHOD 0x80550c13 +#define SCE_NP_MATCHING2_ERROR_INVALID_MAX_SLOT 0x80550c14 +#define SCE_NP_MATCHING2_ERROR_INVALID_OPT_SIZE 0x80550c15 +#define SCE_NP_MATCHING2_ERROR_INVALID_MATCHING_SPACE 0x80550c16 +#define SCE_NP_MATCHING2_ERROR_INVALID_BLOCK_KICK_FLAG 0x80550c18 +#define SCE_NP_MATCHING2_ERROR_INVALID_MESSAGE_TARGET 0x80550c19 +#define SCE_NP_MATCHING2_ERROR_RANGE_FILTER_MAX 0x80550c1a +#define SCE_NP_MATCHING2_ERROR_INVALID_ALIGNMENT 0x80550c1e +#define SCE_NP_MATCHING2_ERROR_CONNECTION_CLOSED_BY_SERVER 0x80550c22 +#define SCE_NP_MATCHING2_ERROR_SSL_VERIFY_FAILED 0x80550c23 +#define SCE_NP_MATCHING2_ERROR_SSL_HANDSHAKE 0x80550c24 +#define SCE_NP_MATCHING2_ERROR_SSL_SEND 0x80550c25 +#define SCE_NP_MATCHING2_ERROR_SSL_RECV 0x80550c26 +#define SCE_NP_MATCHING2_ERROR_JOINED_SESSION_MAX 0x80550c27 +#define SCE_NP_MATCHING2_ERROR_ALREADY_JOINED 0x80550c28 +#define SCE_NP_MATCHING2_ERROR_INVALID_SESSION_TYPE 0x80550c29 +#define SCE_NP_MATCHING2_ERROR_NP_SIGNED_OUT 0x80550c2b +#define SCE_NP_MATCHING2_ERROR_BUSY 0x80550c2c +#define SCE_NP_MATCHING2_ERROR_SERVER_NOT_AVAILABLE 0x80550c2d +#define SCE_NP_MATCHING2_ERROR_NOT_ALLOWED 0x80550c2e +#define SCE_NP_MATCHING2_ERROR_ABORTED 0x80550c2f +#define SCE_NP_MATCHING2_ERROR_REQUEST_NOT_FOUND 0x80550c30 +#define SCE_NP_MATCHING2_ERROR_SESSION_DESTROYED 0x80550c31 +#define SCE_NP_MATCHING2_ERROR_CONTEXT_STOPPED 0x80550c32 +#define SCE_NP_MATCHING2_ERROR_INVALID_REQUEST_PARAMETER 0x80550c33 +#define SCE_NP_MATCHING2_ERROR_NOT_NP_SIGN_IN 0x80550c34 +#define SCE_NP_MATCHING2_ERROR_ROOM_NOT_FOUND 0x80550c35 +#define SCE_NP_MATCHING2_ERROR_ROOM_MEMBER_NOT_FOUND 0x80550c36 +#define SCE_NP_MATCHING2_ERROR_LOBBY_NOT_FOUND 0x80550c37 +#define SCE_NP_MATCHING2_ERROR_LOBBY_MEMBER_NOT_FOUND 0x80550c38 +#define SCE_NP_MATCHING2_ERROR_KEEPALIVE_TIMEOUT 0x80550c3a +#define SCE_NP_MATCHING2_ERROR_TIMEOUT_TOO_SHORT 0x80550c3b +#define SCE_NP_MATCHING2_ERROR_TIMEDOUT 0x80550c3c +#define SCE_NP_MATCHING2_ERROR_INVALID_SLOTGROUP 0x80550c3d +#define SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_SIZE 0x80550c3e +#define SCE_NP_MATCHING2_ERROR_CANNOT_ABORT 0x80550c3f +#define SCE_NP_MATCHING2_ERROR_SESSION_NOT_FOUND 0x80550c40 + +#define SCE_NP_MATCHING2_SERVER_ERROR_BAD_REQUEST 0x80550d01 +#define SCE_NP_MATCHING2_SERVER_ERROR_SERVICE_UNAVAILABLE 0x80550d02 +#define SCE_NP_MATCHING2_SERVER_ERROR_BUSY 0x80550d03 +#define SCE_NP_MATCHING2_SERVER_ERROR_END_OF_SERVICE 0x80550d04 +#define SCE_NP_MATCHING2_SERVER_ERROR_INTERNAL_SERVER_ERROR 0x80550d05 +#define SCE_NP_MATCHING2_SERVER_ERROR_PLAYER_BANNED 0x80550d06 +#define SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN 0x80550d07 +#define SCE_NP_MATCHING2_SERVER_ERROR_BLOCKED 0x80550d08 +#define SCE_NP_MATCHING2_SERVER_ERROR_UNSUPPORTED_NP_ENV 0x80550d09 +#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_TICKET 0x80550d0a +#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_SIGNATURE 0x80550d0b +#define SCE_NP_MATCHING2_SERVER_ERROR_EXPIRED_TICKET 0x80550d0c +#define SCE_NP_MATCHING2_SERVER_ERROR_ENTITLEMENT_REQUIRED 0x80550d0d +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_CONTEXT 0x80550d0e +#define SCE_NP_MATCHING2_SERVER_ERROR_CLOSED 0x80550d0f +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_TITLE 0x80550d10 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_WORLD 0x80550d11 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_LOBBY 0x80550d12 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM 0x80550d13 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_LOBBY_INSTANCE 0x80550d14 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM_INSTANCE 0x80550d15 +#define SCE_NP_MATCHING2_SERVER_ERROR_PASSWORD_MISMATCH 0x80550d17 +#define SCE_NP_MATCHING2_SERVER_ERROR_LOBBY_FULL 0x80550d18 +#define SCE_NP_MATCHING2_SERVER_ERROR_ROOM_FULL 0x80550d19 +#define SCE_NP_MATCHING2_SERVER_ERROR_GROUP_FULL 0x80550d1b +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER 0x80550d1c +#define SCE_NP_MATCHING2_SERVER_ERROR_TITLE_PASSPHRASE_MISMATCH 0x80550d1e +#define SCE_NP_MATCHING2_SERVER_ERROR_CONSOLE_BANNED 0x80550d28 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_ROOMGROUP 0x80550d29 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_GROUP 0x80550d2a +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_PASSWORD 0x80550d2b +#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_GROUP_SLOT_NUM 0x80550d2c +#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_PASSWORD_SLOT_MASK 0x80550d2d +#define SCE_NP_MATCHING2_SERVER_ERROR_DUPLICATE_GROUP_LABEL 0x80550d2e +#define SCE_NP_MATCHING2_SERVER_ERROR_REQUEST_OVERFLOW 0x80550d2f +#define SCE_NP_MATCHING2_SERVER_ERROR_ALREADY_JOINED 0x80550d30 +#define SCE_NP_MATCHING2_SERVER_ERROR_NAT_TYPE_MISMATCH 0x80550d31 +#define SCE_NP_MATCHING2_SERVER_ERROR_ROOM_INCONSISTENCY 0x80550d32 + +#define SCE_NP_MATCHING2_SIGNALING_ERROR_NOT_INITIALIZED 0x80550e01 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_ALREADY_INITIALIZED 0x80550e02 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_OUT_OF_MEMORY 0x80550e03 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTXID_NOT_AVAILABLE 0x80550e04 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTX_NOT_FOUND 0x80550e05 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_REQID_NOT_AVAILABLE 0x80550e06 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_REQ_NOT_FOUND 0x80550e07 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_PARSER_CREATE_FAILED 0x80550e08 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_PARSER_FAILED 0x80550e09 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_INVALID_NAMESPACE 0x80550e0a +#define SCE_NP_MATCHING2_SIGNALING_ERROR_NETINFO_NOT_AVAILABLE 0x80550e0b +#define SCE_NP_MATCHING2_SIGNALING_ERROR_PEER_NOT_RESPONDING 0x80550e0c +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONNID_NOT_AVAILABLE 0x80550e0d +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONN_NOT_FOUND 0x80550e0e +#define SCE_NP_MATCHING2_SIGNALING_ERROR_PEER_UNREACHABLE 0x80550e0f +#define SCE_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_PEER 0x80550e10 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_TIMEOUT 0x80550e11 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTX_MAX 0x80550e12 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_RESULT_NOT_FOUND 0x80550e13 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONN_IN_PROGRESS 0x80550e14 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_INVALID_ARGUMENT 0x80550e15 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_OWN_NP_ID 0x80550e16 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_TOO_MANY_CONN 0x80550e17 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_MYSELF 0x80550e18 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_MATCHING2_PEER_NOT_FOUND 0x80550e19 + +#define SCE_NP_TROPHY_ERROR_UNKNOWN 0x80551600 +#define SCE_NP_TROPHY_ERROR_NOT_INITIALIZED 0x80551601 +#define SCE_NP_TROPHY_ERROR_ALREADY_INITIALIZED 0x80551602 +#define SCE_NP_TROPHY_ERROR_NO_MEMORY 0x80551603 +#define SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT 0x80551604 +#define SCE_NP_TROPHY_ERROR_INSUFFICIENT_BUFFER 0x80551605 +#define SCE_NP_TROPHY_ERROR_EXCEEDS_MAX 0x80551606 +#define SCE_NP_TROPHY_ERROR_ABORT 0x80551607 +#define SCE_NP_TROPHY_ERROR_INVALID_HANDLE 0x80551608 +#define SCE_NP_TROPHY_ERROR_INVALID_CONTEXT 0x80551609 +#define SCE_NP_TROPHY_ERROR_INVALID_NPCOMMID 0x8055160a +#define SCE_NP_TROPHY_ERROR_INVALID_NPCOMMSIGN 0x8055160b + +#define SCE_NP_BASIC_ERROR_BASE 0x80551d00 +#define SCE_NP_BASIC_ERROR_UNKNOWN 0x80551d01 +#define SCE_NP_BASIC_ERROR_INVALID_ARGUMENT 0x80551d02 +#define SCE_NP_BASIC_ERROR_OUT_OF_MEMORY 0x80551d03 +#define SCE_NP_BASIC_ERROR_NOT_INITIALIZED 0x80551d04 +#define SCE_NP_BASIC_ERROR_ALREADY_INITIALIZED 0x80551d05 +#define SCE_NP_BASIC_ERROR_SIGNED_OUT 0x80551d06 +#define SCE_NP_BASIC_ERROR_NOT_ONLINE 0x80551d07 +#define SCE_NP_BASIC_ERROR_DATA_NOT_FOUND 0x80551d08 +#define SCE_NP_BASIC_ERROR_BUSY 0x80551d09 +#define SCE_NP_BASIC_ERROR_NOT_READY_TO_COMMUNICATE 0x80551d0a +#define SCE_NP_BASIC_ERROR_NO_COMM_ID_SUPPLIED 0x80551d0b // Based on https://github.com/RPCS3/rpcs3/blob/psp2/rpcs3/Emu/PSP2/Modules/sceNpCommon.h enum SceNpServiceState : s32 @@ -82,6 +341,7 @@ struct SceNpCommunicationConfig PSPPointer commSignature; }; +// Part of BCP 47 Code (ie. "fr" for France/French)? struct SceNpCountryCode { char data[2]; @@ -117,6 +377,7 @@ struct SceNpUserInformation u8 reserved[52]; }; +// Language Code (ie. 1033 for "en-US")? struct SceNpMyLanguages { s32_le language1; @@ -172,8 +433,13 @@ struct NpAuthHandler { u32 argument; }; -struct NpAuthArgs { +union NpAuthArgs { u32_le data[3]; // id, result, ArgAddr + struct { + s32_le id; + s32_le result; + u32_le argAddr; + }; }; using SceNpAuthCallback = s32(s32 id, s32 result, PSPPointer arg); @@ -227,9 +493,9 @@ struct SceNpEntitlement // Tickets data are in big-endian based on captured packets struct SceNpTicketParamData { - u16_be type; - u16_be length; - //u8 value[]; // optional data + u16_be type; // 0(NULL), 1(32-bit int), 2(64-bi long), 4(ansi string?), 7(date/timestamp), 8(ascii string) + u16_be length; // size of the following data value + //u8 value[]; // optional data of length size }; struct SceNpTicketHeader @@ -242,7 +508,7 @@ struct SceNpTicketHeader // A section can contain other sections or param data, thus sharing their enum/def? struct SceNpTicketSection { - u16_be type; // section type? ie. 30 XX where known XX are 00, 02, 10, 11 + u16_be type; // section type? ie. 30 XX where known XX are 00(Body), 02(Footer), 10, 11 u16_be size; // total section size (excluding this 4-bytes section delimiter struct) }; @@ -250,10 +516,127 @@ struct SceNpTicket { SceNpTicketHeader header; SceNpTicketSection section; // Body or Parameter sections? - //SceNpTicketParamData parameters[]; // a list of TicketParamData + //SceNpTicketParamData parameters[]; // a list of TicketParamData following the section //u8 unknownBytes[]; // optional data? }; +struct SceNpAuthMemoryStat { + int npMemSize; // Memory allocated by the NP utility. Pool Size? + int npMaxMemSize; // Maximum memory used by the NP utility. + int npFreeMemSize; // Free memory available to use by the NP utility. +}; + + +// Based on https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.h (Just as reference, might be slightly different than PSP) +// Event of request functions +enum PS3Matching2RequestEvent +{ + SCE_NP_MATCHING2_REQUEST_EVENT_GetServerInfo = 0x0001, + SCE_NP_MATCHING2_REQUEST_EVENT_GetWorldInfoList = 0x0002, + SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataExternalList = 0x0003, + SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal = 0x0004, + SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList = 0x0005, + SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyInfoList = 0x0006, + SCE_NP_MATCHING2_REQUEST_EVENT_SetUserInfo = 0x0007, + SCE_NP_MATCHING2_REQUEST_EVENT_GetUserInfoList = 0x0008, + SCE_NP_MATCHING2_REQUEST_EVENT_CreateServerContext = 0x0009, + SCE_NP_MATCHING2_REQUEST_EVENT_DeleteServerContext = 0x000a, + SCE_NP_MATCHING2_REQUEST_EVENT_CreateJoinRoom = 0x0101, + SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom = 0x0102, + SCE_NP_MATCHING2_REQUEST_EVENT_LeaveRoom = 0x0103, + SCE_NP_MATCHING2_REQUEST_EVENT_GrantRoomOwner = 0x0104, + SCE_NP_MATCHING2_REQUEST_EVENT_KickoutRoomMember = 0x0105, + SCE_NP_MATCHING2_REQUEST_EVENT_SearchRoom = 0x0106, + SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomChatMessage = 0x0107, + SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomMessage = 0x0108, + SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataInternal = 0x0109, + SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataInternal = 0x010a, + SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomMemberDataInternal = 0x010b, + SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataInternal = 0x010c, + SCE_NP_MATCHING2_REQUEST_EVENT_SetSignalingOptParam = 0x010d, + SCE_NP_MATCHING2_REQUEST_EVENT_JoinLobby = 0x0201, + SCE_NP_MATCHING2_REQUEST_EVENT_LeaveLobby = 0x0202, + SCE_NP_MATCHING2_REQUEST_EVENT_SendLobbyChatMessage = 0x0203, + SCE_NP_MATCHING2_REQUEST_EVENT_SendLobbyInvitation = 0x0204, + SCE_NP_MATCHING2_REQUEST_EVENT_SetLobbyMemberDataInternal = 0x0205, + SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyMemberDataInternal = 0x0206, + SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyMemberDataInternalList = 0x0207, + SCE_NP_MATCHING2_REQUEST_EVENT_SignalingGetPingInfo = 0x0e01, +}; + +// Based on decompiled np_matching2.prx, commented with syscalls where the event id is being used +#define PSP_NP_MATCHING2_EVENT_0001 0x0001 // GetServerInfo +#define PSP_NP_MATCHING2_EVENT_0002 0x0002 // GetWorldInfoList +#define PSP_NP_MATCHING2_EVENT_0003 0x0003 // SetUserInfo +#define PSP_NP_MATCHING2_EVENT_0004 0x0004 // GetUserInfoList +#define PSP_NP_MATCHING2_EVENT_0005 0x0005 // GetRoomMemberDataExternalList +#define PSP_NP_MATCHING2_EVENT_0006 0x0006 // SetRoomDataExternal +#define PSP_NP_MATCHING2_EVENT_0007 0x0007 // GetRoomDataExternalList + +#define PSP_NP_MATCHING2_EVENT_0101 0x0101 // CreateJoinRoom +#define PSP_NP_MATCHING2_EVENT_0102 0x0102 // JoinRoom +#define PSP_NP_MATCHING2_EVENT_0103 0x0103 // LeaveRoom +#define PSP_NP_MATCHING2_EVENT_0104 0x0104 // GrantRoomOwner +#define PSP_NP_MATCHING2_EVENT_0105 0x0105 // KickoutRoomMember +#define PSP_NP_MATCHING2_EVENT_0106 0x0106 // SearchRoom +#define PSP_NP_MATCHING2_EVENT_0107 0x0107 // SendRoomChatMessage +#define PSP_NP_MATCHING2_EVENT_0108 0x0108 // SendRoomMessage, also used on various places (internal function) +#define PSP_NP_MATCHING2_EVENT_0109 0x0109 // SetRoomDataInternal +#define PSP_NP_MATCHING2_EVENT_010A 0x010A // GetRoomDataInternal +#define PSP_NP_MATCHING2_EVENT_010B 0x010B // SetRoomMemberDataInternal +#define PSP_NP_MATCHING2_EVENT_010C 0x010C // GetRoomMemberDataInternal +#define PSP_NP_MATCHING2_EVENT_010D 0x010D // GetRoomMemberDataInternalList +#define PSP_NP_MATCHING2_EVENT_010E 0x010E // SetSignalingOptParam + +#define PSP_NP_MATCHING2_EVENT_A102 0xA102 // Used on various places (internal function) + +// Either this is an ID, state/status, flags, or might be size of data? +#define PSP_NP_MATCHING2_STATE_1001 0x1001 +#define PSP_NP_MATCHING2_STATE_1006 0x1006 +#define PSP_NP_MATCHING2_STATE_1007 0x1007 +#define PSP_NP_MATCHING2_STATE_1008 0x1008 + +#define PSP_NP_MATCHING2_STATE_1200 0x1200 +#define PSP_NP_MATCHING2_STATE_1206 0x1206 +#define PSP_NP_MATCHING2_STATE_1207 0x1207 +#define PSP_NP_MATCHING2_STATE_1208 0x1208 +#define PSP_NP_MATCHING2_STATE_1209 0x1209 +#define PSP_NP_MATCHING2_STATE_120B 0x120B +#define PSP_NP_MATCHING2_STATE_120C 0x120C + +#define PSP_NP_MATCHING2_STATE_3202 0x3202 +#define PSP_NP_MATCHING2_STATE_3203 0x3203 +#define PSP_NP_MATCHING2_STATE_3204 0x3204 +#define PSP_NP_MATCHING2_STATE_3205 0x3205 +#define PSP_NP_MATCHING2_STATE_3206 0x3206 +#define PSP_NP_MATCHING2_STATE_3207 0x3207 +#define PSP_NP_MATCHING2_STATE_3208 0x3208 +#define PSP_NP_MATCHING2_STATE_320A 0x320A +#define PSP_NP_MATCHING2_STATE_3210 0x3210 +#define PSP_NP_MATCHING2_STATE_3211 0x3211 + +#define PSP_NP_MATCHING2_MAX_CONTEXTID 7; + +struct NpMatching2Handler { + u32 entryPoint; + u32 argument; +}; + +// Arg1 and Arg2 seems to be a pair and predefined: 0x0001 with 0x1001, 0x0002 with 0x1008, 0x0003 with 0x1006, 0x0004 with 0x1007, +// 0x0005 with 0x1206, 0x0006 with 0x1207, 0x0007 with 0x1208, 0x0101 with 0x1209, 0x0102 with 0x1209, 0x0103 with 0x3202, +// 0x0104 with 0x3210, 0x0105 with 0x3211, 0x0106 with 2 possibilities (0x1200 and 0x120c), 0x0107 with 0x3208, 0x0108 with 0x320a, +// 0x0109 with 0x3204, 0x010a with 0x3205, 0x010b with 0x3206, 0x010c with 0x3207, 0x010d with 0x3203, 0x010e with 0x3204, +// 0xa102 with 0x120b. +// Arg5 seems to be boolean (0/1), mostly 0, conditional when Arg1=0x0001 +// Arg7 seems to be integer/state? (0..2), mostly 0, conditional when Arg1=0x0108 (0 on SendRoomMessage, 2 on others), 1 when Arg1=0xa102 +struct NpMatching2Args { + u32_le data[11]; // 7 elements (excluding optional data)? or may be 11 elements (including optional data)? + // May be followed by optional data? since these Args usually created on the stack +}; + +#pragma pack(pop) + + #define PARENTAL_CONTROL_DISABLED 0 #define PARENTAL_CONTROL_ENABLED 1 @@ -261,22 +644,35 @@ struct SceNpTicket #define STATUS_ACCOUNT_CHAT_RESTRICTED 0x100 #define STATUS_ACCOUNT_PARENTAL_CONTROL_ENABLED 0x200 -struct SceNpAuthMemoryStat { - int npMemSize; // Memory allocated by the NP utility. - int npMaxMemSize; // Maximum memory used by the NP utility. - int npFreeMemSize; // Free memory available to use by the NP utility. -}; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif +#define NP_SIGNIN_STATUS_NONE 0 // SIGNEDOUT? +#define NP_SIGNIN_STATUS_SUCCESS 1 +#define NP_SIGNIN_STATUS_CANCELED 2 +#define NP_SIGNIN_STATUS_FAILED 3 // ERROR/ABORTED/SIGNEDOUT? +// Used by PSPNpSigninDialog.cpp +extern int npSigninState; +extern PSPTimeval npSigninTimestamp; +// Used by sceNet.cpp since we're borrowing Apctl's PSPThread to process NP events & callbacks. +// TODO: NP events should be processed on it's own PSPThread extern std::recursive_mutex npAuthEvtMtx; extern std::deque npAuthEvents; extern std::map npAuthHandlers; +// Used by sceNp2.cpp +extern SceNpCommunicationId npTitleId; + +int NpGetNpId(SceNpId* npid); + +int sceNpAuthGetMemoryStat(u32 memStatAddr); +int sceNpAuthCreateStartRequest(u32 paramAddr); +int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length); +int sceNpAuthGetEntitlementById(u32 ticketBufferAddr, u32 ticketLength, u32 entitlementIdAddr, u32 arg4); +int sceNpAuthAbortRequest(int requestId); +int sceNpAuthDestroyRequest(int requestId); + void Register_sceNp(); -void Register_sceNpCommerce2(); void Register_sceNpService(); void Register_sceNpAuth(); +void Register_sceNpCommerce2(); +void Register_sceNpMatching2(); From dcf3ece8f41bfa134212499ee0091c56a541d51f Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Fri, 12 Mar 2021 14:32:33 +0700 Subject: [PATCH 31/35] Implement NP Signin Dialog (faked signin) --- CMakeLists.txt | 2 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 + Core/Dialog/PSPNpSigninDialog.cpp | 349 ++++++++++++++++++++++++++++ Core/Dialog/PSPNpSigninDialog.h | 67 ++++++ Core/HLE/sceUtility.cpp | 49 +++- Core/HLE/sceUtility.h | 1 + UWP/CoreUWP/CoreUWP.vcxproj | 2 + UWP/CoreUWP/CoreUWP.vcxproj.filters | 6 + android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 11 files changed, 481 insertions(+), 5 deletions(-) create mode 100644 Core/Dialog/PSPNpSigninDialog.cpp create mode 100644 Core/Dialog/PSPNpSigninDialog.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d4b2fdc242..8fe807763f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1709,6 +1709,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/Dialog/PSPMsgDialog.h Core/Dialog/PSPNetconfDialog.cpp Core/Dialog/PSPNetconfDialog.h + Core/Dialog/PSPNpSigninDialog.cpp + Core/Dialog/PSPNpSigninDialog.h Core/Dialog/PSPOskDialog.cpp Core/Dialog/PSPOskDialog.h Core/Dialog/PSPPlaceholderDialog.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 05bdb72eae..bb5688fb30 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -572,6 +572,7 @@ + @@ -1118,6 +1119,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index e7a1ff33e2..8fc7db771d 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -523,6 +523,9 @@ Dialog + + Dialog + Debugger @@ -1597,6 +1600,9 @@ Dialog + + Dialog + MIPS\JitCommon diff --git a/Core/Dialog/PSPNpSigninDialog.cpp b/Core/Dialog/PSPNpSigninDialog.cpp new file mode 100644 index 0000000000..f6621db66c --- /dev/null +++ b/Core/Dialog/PSPNpSigninDialog.cpp @@ -0,0 +1,349 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#if defined(_WIN32) +#include "Common/CommonWindows.h" +#endif +#include +#include "Common/Data/Text/I18n.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Core/Config.h" +#include "Core/MemMapHelpers.h" +#include "Core/Util/PPGeDraw.h" +#include "Core/HLE/sceKernelMemory.h" +#include "Core/HLE/sceCtrl.h" +#include "Core/HLE/sceUtility.h" +#include "Core/HLE/sceNet.h" +#include "Core/HLE/sceNetAdhoc.h" +#include "Core/HLE/sceNp.h" +#include "Core/Dialog/PSPNpSigninDialog.h" +#include "Common/Data/Encoding/Utf8.h" +#include "Core/Reporting.h" + + +static const float FONT_SCALE = 0.65f; + +// Needs testing. +const static int NP_INIT_DELAY_US = 200000; +const static int NP_SHUTDOWN_DELAY_US = 501000; +const static int NP_RUNNING_DELAY_US = 1000000; // faked delay to simulate signin process to give chance for players to read the text on the dialog + +PSPNpSigninDialog::PSPNpSigninDialog(UtilityDialogType type) : PSPDialog(type) { +} + +PSPNpSigninDialog::~PSPNpSigninDialog() { +} + +int PSPNpSigninDialog::Init(u32 paramAddr) { + // Already running + if (ReadStatus() != SCE_UTILITY_STATUS_NONE) + return SCE_ERROR_UTILITY_INVALID_STATUS; + + requestAddr = paramAddr; + int size = Memory::Read_U32(paramAddr); + memset(&request, 0, sizeof(request)); + // Only copy the right size to support different request format + Memory::Memcpy(&request, paramAddr, size); + + WARN_LOG_REPORT_ONCE(PSPNpSigninDialogInit, SCENET, "NpSignin Init Params: %08x, %08x, %08x, %08x", request.npSigninStatus, request.unknown1, request.unknown2, request.unknown3); + + ChangeStatusInit(NP_INIT_DELAY_US); + + // Eat any keys pressed before the dialog inited. + UpdateButtons(); + okButtonImg = ImageID("I_CIRCLE"); + cancelButtonImg = ImageID("I_CROSS"); + okButtonFlag = CTRL_CIRCLE; + cancelButtonFlag = CTRL_CROSS; + if (request.common.buttonSwap == 1) + { + okButtonImg = ImageID("I_CROSS"); + cancelButtonImg = ImageID("I_CIRCLE"); + okButtonFlag = CTRL_CROSS; + cancelButtonFlag = CTRL_CIRCLE; + } + + //npSigninResult = -1; + startTime = (u64)(time_now_d() * 1000000.0); + step = 0; + + StartFade(true); + return 0; +} + +void PSPNpSigninDialog::DrawBanner() { + + PPGeDrawRect(0, 0, 480, 22, CalcFadedColor(0x65636358)); + + PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f); + textStyle.hasShadow = false; + + // TODO: Draw a hexagon icon + PPGeDrawImage(10, 5, 11.0f, 10.0f, 1, 10, 1, 10, 10, 10, FadedImageStyle()); + auto di = GetI18NCategory("Dialog"); + PPGeDrawText(di->T("Sign In"), 31, 10, textStyle); +} + +void PSPNpSigninDialog::DrawIndicator() { + // TODO: Draw animated circle as processing indicator + PPGeDrawImage(456, 248, 20.0f, 20.0f, 1, 10, 1, 10, 10, 10, FadedImageStyle()); +} + +void PSPNpSigninDialog::DrawLogo() { + // TODO: Draw OpenDNAS logo + PPGeDrawImage(416, 22, 64.0f, 64.0f, 1, 10, 1, 10, 64, 64, FadedImageStyle()); +} + +void PSPNpSigninDialog::DisplayMessage(std::string text1, std::string text2a, std::string text2b, std::string text3a, std::string text3b, bool hasYesNo, bool hasOK) { + auto di = GetI18NCategory("Dialog"); + + PPGeStyle buttonStyle = FadedStyle(PPGeAlign::BOX_CENTER, FONT_SCALE); + PPGeStyle messageStyle = FadedStyle(PPGeAlign::BOX_HCENTER, FONT_SCALE); + PPGeStyle messageStyleRight = FadedStyle(PPGeAlign::BOX_RIGHT, FONT_SCALE); + PPGeStyle messageStyleLeft = FadedStyle(PPGeAlign::BOX_LEFT, FONT_SCALE); + + std::string text2 = text2a + " " + text2b; + std::string text3 = text3a + " " + text3b; + + // Without the scrollbar, we have 350 total pixels. + float WRAP_WIDTH = 300.0f; + if (UTF8StringNonASCIICount(text1.c_str()) >= (int)text1.size() / 4) { + WRAP_WIDTH = 336.0f; + if (text1.size() > 12) { + messageStyle.scale = 0.6f; + } + } + + float totalHeight1 = 0.0f; + PPGeMeasureText(nullptr, &totalHeight1, text1.c_str(), FONT_SCALE, PPGE_LINE_WRAP_WORD, WRAP_WIDTH); + float totalHeight2 = 0.0f; + if (text2 != " ") + PPGeMeasureText(nullptr, &totalHeight2, text2.c_str(), FONT_SCALE, PPGE_LINE_USE_ELLIPSIS, WRAP_WIDTH); + float totalHeight3 = 0.0f; + if (text3 != " ") + PPGeMeasureText(nullptr, &totalHeight3, text3.c_str(), FONT_SCALE, PPGE_LINE_USE_ELLIPSIS, WRAP_WIDTH); + float marginTop = 0.0f; + if (text2 != " " || text3 != " ") + marginTop = 11.0f; + float totalHeight = totalHeight1 + totalHeight2 + totalHeight3 + marginTop; + // The PSP normally only shows about 8 lines at a time. + // For improved UX, we intentionally show part of the next line. + float visibleHeight = std::min(totalHeight, 175.0f); + float h2 = visibleHeight / 2.0f; + + float centerY = 135.0f; + float sy = centerY - h2 - 15.0f; + float ey = centerY + h2 + 20.0f; + float buttonY = centerY + h2 + 5.0f; + + auto drawSelectionBoxAndAdjust = [&](float x) { + // Box has a fixed size. + float w = 15.0f; + float h = 8.0f; + PPGeDrawRect(x - w, buttonY - h, x + w, buttonY + h, CalcFadedColor(0x6DCFCFCF)); + + centerY -= h + 5.0f; + sy -= h + 5.0f; + ey = buttonY + h * 2.0f + 5.0f; + }; + + if (hasYesNo) { + if (yesnoChoice == 1) { + drawSelectionBoxAndAdjust(204.0f); + } + else { + drawSelectionBoxAndAdjust(273.0f); + } + + PPGeDrawText(di->T("Yes"), 203.0f, buttonY - 1.0f, buttonStyle); + PPGeDrawText(di->T("No"), 272.0f, buttonY - 1.0f, buttonStyle); + if (IsButtonPressed(CTRL_LEFT) && yesnoChoice == 0) { + yesnoChoice = 1; + } + else if (IsButtonPressed(CTRL_RIGHT) && yesnoChoice == 1) { + yesnoChoice = 0; + } + buttonY += 8.0f + 5.0f; + } + + if (hasOK) { + drawSelectionBoxAndAdjust(240.0f); + + PPGeDrawText(di->T("OK"), 239.0f, buttonY - 1.0f, buttonStyle); + buttonY += 8.0f + 5.0f; + } + + PPGeScissor(0, (int)(centerY - h2 - 2), 480, (int)(centerY + h2 + 2)); + PPGeDrawTextWrapped(text1.c_str(), 240.0f, centerY - h2 - scrollPos_, WRAP_WIDTH, 0, messageStyle); + if (text2a != "") { + if (text2b != "") + PPGeDrawTextWrapped(text2a.c_str(), 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleRight); + else + PPGeDrawTextWrapped(text2a.c_str(), 240.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyle); + } + if (text2b != "") + PPGeDrawTextWrapped(text2b.c_str(), 240.0f + 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleLeft); + if (text3a != "") { + if (text3b != "") + PPGeDrawTextWrapped(text3a.c_str(), 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleRight); + else + PPGeDrawTextWrapped(text3a.c_str(), 240.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyle); + } + if (text3b != "") + PPGeDrawTextWrapped(text3b.c_str(), 240.0f + 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleLeft); + PPGeScissorReset(); + + // Do we need a scrollbar? + if (visibleHeight < totalHeight) { + float scrollSpeed = 5.0f; + float scrollMax = totalHeight - visibleHeight; + + float bobHeight = (visibleHeight / totalHeight) * visibleHeight; + float bobOffset = (scrollPos_ / scrollMax) * (visibleHeight - bobHeight); + float bobY1 = centerY - h2 + bobOffset; + PPGeDrawRect(415.0f, bobY1, 420.0f, bobY1 + bobHeight, CalcFadedColor(0xFFCCCCCC)); + + auto buttonDown = [this](int btn, int& held) { + if (IsButtonPressed(btn)) { + held = 0; + return true; + } + return IsButtonHeld(btn, held, 1, 1); + }; + if (buttonDown(CTRL_DOWN, framesDownHeld_) && scrollPos_ < scrollMax) { + scrollPos_ = std::min(scrollMax, scrollPos_ + scrollSpeed); + } + if (buttonDown(CTRL_UP, framesUpHeld_) && scrollPos_ > 0.0f) { + scrollPos_ = std::max(0.0f, scrollPos_ - scrollSpeed); + } + } + + PPGeDrawRect(60.0f, sy, 420.0f, sy + 1.0f, CalcFadedColor(0xFFFFFFFF)); + PPGeDrawRect(60.0f, ey, 420.0f, ey + 1.0f, CalcFadedColor(0xFFFFFFFF)); +} + +int PSPNpSigninDialog::Update(int animSpeed) { + if (ReadStatus() != SCE_UTILITY_STATUS_RUNNING) { + return SCE_ERROR_UTILITY_INVALID_STATUS; + } + + UpdateButtons(); + auto di = GetI18NCategory("Dialog"); + auto err = GetI18NCategory("Error"); + u64 now = (u64)(time_now_d() * 1000000.0); + + if (request.npSigninStatus == NP_SIGNIN_STATUS_NONE) { + UpdateFade(animSpeed); + StartDraw(); + + PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0xC0C8B2AC)); + DrawBanner(); + DrawIndicator(); + + // TODO: Not sure what should happen here.. may be something like this https://pastebin.com/1eW48zBb ? but we can do test on Open DNAS Server later https://dnas.hashsploit.net/us-gw/ + // DNAS dialog + if (step >= 2 && now - startTime > NP_RUNNING_DELAY_US) { + DrawLogo(); + DisplayMessage(di->T("PleaseWait", "Please wait...")); + step++; + } + // Signin dialog + else { + // Skipping the Select Connection screen since we only have 1 fake profile + DisplayMessage(di->T("SigninPleaseWait", "Signing in...\nPlease wait.")); + } + DisplayButtons(DS_BUTTON_CANCEL, di->T("Cancel")); + + if (step >= 2 && now - startTime > NP_RUNNING_DELAY_US*2) { + if (pendingStatus != SCE_UTILITY_STATUS_FINISHED) { + StartFade(false); + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NP_SHUTDOWN_DELAY_US); + step++; + } + } + + else if (step == 1 && now - startTime > NP_RUNNING_DELAY_US) { + // Switch to the next message (with DNAS logo) + StartFade(true); + step++; + } + + else if (step == 0) { + /*if (npAuthResult < 0 && request.NpSigninData.IsValid()) { + npAuthResult = sceNpAuthCreateStartRequest(request.NpSigninData->paramAddr); + }*/ + step++; + } + + if (/*npAuthResult >= 0 &&*/ IsButtonPressed(cancelButtonFlag)) { + StartFade(false); + //sceNpAuthAbortRequest(npAuthResult); + //sceNpAuthDestroyRequest(npAuthResult); + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NP_SHUTDOWN_DELAY_US); + request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT; + request.npSigninStatus = NP_SIGNIN_STATUS_CANCELED; + //step = 0; + } + + EndDraw(); + } + + if (ReadStatus() == SCE_UTILITY_STATUS_FINISHED || pendingStatus == SCE_UTILITY_STATUS_FINISHED) { + npSigninState = NP_SIGNIN_STATUS_SUCCESS; + __RtcTimeOfDay(&npSigninTimestamp); + request.npSigninStatus = npSigninState; + } + return 0; +} + +int PSPNpSigninDialog::Shutdown(bool force) { + if (ReadStatus() != SCE_UTILITY_STATUS_FINISHED && !force) + return SCE_ERROR_UTILITY_INVALID_STATUS; + + PSPDialog::Shutdown(force); + if (!force) { + ChangeStatusShutdown(NP_SHUTDOWN_DELAY_US); + } + + // FIXME: This should probably be done within FinishShutdown to prevent some games (ie. UNO) from progressing further while the Dialog is still being faded-out, since we can't override non-virtual method... so here is the closes one to FinishShutdown. + if (Memory::IsValidAddress(requestAddr)) // Need to validate first to prevent Invalid address when the game is being Shutdown/Exited to menu + Memory::Memcpy(requestAddr, &request, request.common.size, "NpSigninDialogParam"); + + return 0; +} + +void PSPNpSigninDialog::DoState(PointerWrap &p) { + PSPDialog::DoState(p); + + auto s = p.Section("PSPNpSigninDialog", 1, 1); + if (!s) + return; + + Do(p, request); + Do(p, step); + //Do(p, npSigninResult); + + if (p.mode == p.MODE_READ) { + startTime = 0; + } +} + +pspUtilityDialogCommon* PSPNpSigninDialog::GetCommonParam() +{ + return &request.common; +} diff --git a/Core/Dialog/PSPNpSigninDialog.h b/Core/Dialog/PSPNpSigninDialog.h new file mode 100644 index 0000000000..15aac7b0c9 --- /dev/null +++ b/Core/Dialog/PSPNpSigninDialog.h @@ -0,0 +1,67 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "Core/Dialog/PSPDialog.h" +#include "Core/MemMapHelpers.h" + + +struct SceUtilityNpSigninParam { + pspUtilityDialogCommon common; + // Initially all zero? Or is there a possibility for one of these unknown to be a buffer to a packet data if it wasn't null? + int npSigninStatus; + int unknown1; + int unknown2; + int unknown3; +}; + + +class PSPNpSigninDialog: public PSPDialog { +public: + PSPNpSigninDialog(UtilityDialogType type); + virtual ~PSPNpSigninDialog(); + + virtual int Init(u32 paramAddr); + virtual int Update(int animSpeed) override; + virtual int Shutdown(bool force = false) override; + virtual void DoState(PointerWrap &p) override; + virtual pspUtilityDialogCommon* GetCommonParam() override; + +protected: + bool UseAutoStatus() override { + return false; + } + +private: + void DisplayMessage(std::string text1, std::string text2a = "", std::string text2b = "", std::string text3a = "", std::string text3b = "", bool hasYesNo = false, bool hasOK = false); + void DrawBanner(); + void DrawIndicator(); + void DrawLogo(); + + SceUtilityNpSigninParam request = {}; + u32 requestAddr = 0; + //int npSigninResult = -1; + + int yesnoChoice = 0; + float scrollPos_ = 0.0f; + int framesUpHeld_ = 0; + int framesDownHeld_ = 0; + + u64 startTime = 0; + int step = 0; +}; diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index c5bdde62f8..e6a5124600 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -47,6 +47,7 @@ #include "Core/Dialog/PSPOskDialog.h" #include "Core/Dialog/PSPGamedataInstallDialog.h" #include "Core/Dialog/PSPNetconfDialog.h" +#include "Core/Dialog/PSPNpSigninDialog.h" #include "Core/Dialog/PSPScreenshotDialog.h" #define PSP_AV_MODULE_AVCODEC 0 @@ -132,6 +133,7 @@ static PSPOskDialog *oskDialog; static PSPNetconfDialog *netDialog; static PSPScreenshotDialog *screenshotDialog; static PSPGamedataInstallDialog *gamedataInstallDialog; +static PSPNpSigninDialog *npSigninDialog; static int oldStatus = -1; static std::map currentlyLoadedModules; @@ -195,6 +197,8 @@ static PSPDialog *CurrentDialog(UtilityDialogType type) { break; case UtilityDialogType::GAMEDATAINSTALL: return gamedataInstallDialog; + case UtilityDialogType::NPSIGNIN: + return npSigninDialog; } return nullptr; } @@ -212,6 +216,7 @@ void __UtilityInit() { netDialog = new PSPNetconfDialog(UtilityDialogType::NET); screenshotDialog = new PSPScreenshotDialog(UtilityDialogType::SCREENSHOT); gamedataInstallDialog = new PSPGamedataInstallDialog(UtilityDialogType::GAMEDATAINSTALL); + npSigninDialog = new PSPNpSigninDialog(UtilityDialogType::NPSIGNIN); currentDialogType = UtilityDialogType::NONE; DeactivateDialog(); @@ -221,7 +226,7 @@ void __UtilityInit() { } void __UtilityDoState(PointerWrap &p) { - auto s = p.Section("sceUtility", 1, 5); + auto s = p.Section("sceUtility", 1, 6); if (!s) { return; } @@ -267,6 +272,10 @@ void __UtilityDoState(PointerWrap &p) { if (s >= 5) Do(p, accessThreadFinished); + if (s >= 6) { + npSigninDialog->DoState(p); + } + if (!hasAccessThread && accessThread) { accessThread->Forget(); delete accessThread; @@ -282,6 +291,7 @@ void __UtilityShutdown() { netDialog->Shutdown(true); screenshotDialog->Shutdown(true); gamedataInstallDialog->Shutdown(true); + npSigninDialog->Shutdown(true); if (accessThread) { delete accessThread; @@ -296,6 +306,7 @@ void __UtilityShutdown() { delete netDialog; delete screenshotDialog; delete gamedataInstallDialog; + delete npSigninDialog; } void UtilityDialogInitialize(UtilityDialogType type, int delayUs, int priority) { @@ -884,15 +895,43 @@ static u32 sceUtilityUnloadNetModule(u32 module) } static int sceUtilityNpSigninInitStart(u32 paramsPtr) { - return hleLogError(SCEUTILITY, 0, "not implemented"); + if (currentDialogActive && currentDialogType != UtilityDialogType::NPSIGNIN) { + return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + } + + ActivateDialog(UtilityDialogType::NPSIGNIN); + return hleLogSuccessInfoI(SCEUTILITY, npSigninDialog->Init(paramsPtr)); +} + +static int sceUtilityNpSigninShutdownStart() { + if (currentDialogType != UtilityDialogType::NPSIGNIN) { + return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + } + + DeactivateDialog(); + return hleLogSuccessI(SCEUTILITY, npSigninDialog->Shutdown()); } static int sceUtilityNpSigninUpdate(int animSpeed) { - return hleLogError(SCEUTILITY, 0, "not implemented"); + if (currentDialogType != UtilityDialogType::NPSIGNIN) { + return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + } + + return hleLogSuccessI(SCEUTILITY, npSigninDialog->Update(animSpeed)); } static int sceUtilityNpSigninGetStatus() { - return hleLogError(SCEUTILITY, 0, "not implemented"); + if (currentDialogType != UtilityDialogType::NPSIGNIN) { + return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + } + + int status = npSigninDialog->GetStatus(); + CleanupDialogThreads(); + if (oldStatus != status) { + oldStatus = status; + return hleLogSuccessI(SCEUTILITY, status); + } + return hleLogSuccessVerboseI(SCEUTILITY, status); } static void sceUtilityInstallInitStart(u32 unknown) @@ -1066,7 +1105,7 @@ const HLEFunction sceUtility[] = {0X180F7B62, &WrapI_V, "sceUtilityGamedataInstallAbort", 'i', "" }, {0X16D02AF0, &WrapI_U, "sceUtilityNpSigninInitStart", 'i', "x" }, - {0XE19C97D6, nullptr, "sceUtilityNpSigninShutdownStart", 'i', "" }, + {0XE19C97D6, &WrapI_V, "sceUtilityNpSigninShutdownStart", 'i', "" }, {0XF3FBC572, &WrapI_I, "sceUtilityNpSigninUpdate", 'i', "i" }, {0X86ABDB1B, &WrapI_V, "sceUtilityNpSigninGetStatus", 'i', "" }, diff --git a/Core/HLE/sceUtility.h b/Core/HLE/sceUtility.h index d7358a9ae5..9943fc8399 100644 --- a/Core/HLE/sceUtility.h +++ b/Core/HLE/sceUtility.h @@ -85,6 +85,7 @@ enum class UtilityDialogType { SCREENSHOT, GAMESHARING, GAMEDATAINSTALL, + NPSIGNIN, }; void __UtilityInit(); diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index d1e9ec4366..16863bd6e9 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -415,6 +415,7 @@ + @@ -650,6 +651,7 @@ + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index 466e7867e9..6ceb09e6b5 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -539,6 +539,9 @@ Dialog + + Dialog + Dialog @@ -1539,6 +1542,9 @@ Dialog + + Dialog + Dialog diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 03dd60d89e..33db892245 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -439,6 +439,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/Dialog/PSPGamedataInstallDialog.cpp \ $(SRC)/Core/Dialog/PSPMsgDialog.cpp \ $(SRC)/Core/Dialog/PSPNetconfDialog.cpp \ + $(SRC)/Core/Dialog/PSPNpSigninDialog.cpp \ $(SRC)/Core/Dialog/PSPOskDialog.cpp \ $(SRC)/Core/Dialog/PSPScreenshotDialog.cpp \ $(SRC)/Core/Dialog/PSPPlaceholderDialog.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 37e42af0ee..dca3bde0d1 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -459,6 +459,7 @@ SOURCES_CXX += \ $(COREDIR)/Dialog/PSPGamedataInstallDialog.cpp \ $(COREDIR)/Dialog/PSPMsgDialog.cpp \ $(COREDIR)/Dialog/PSPNetconfDialog.cpp \ + $(COREDIR)/Dialog/PSPNpSigninDialog.cpp \ $(COREDIR)/Dialog/PSPOskDialog.cpp \ $(COREDIR)/Dialog/PSPSaveDialog.cpp \ $(COREDIR)/Dialog/PSPScreenshotDialog.cpp \ From 41de63f13c6fcfbafb291bd3f2287081e22de092 Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Sat, 5 Mar 2022 19:58:09 +0700 Subject: [PATCH 32/35] Moving sceNpMatching2-stuff to sceNp2.cpp/h. PS: Register_sceNpMatching2 not being added to HLETables because currently the callback didn't work properly yet and could crash the game. --- CMakeLists.txt | 2 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 + Core/HLE/sceNp.cpp | 539 -------------------------- Core/HLE/sceNp.h | 233 +----------- Core/HLE/sceNp2.cpp | 566 ++++++++++++++++++++++++++++ Core/HLE/sceNp2.h | 254 +++++++++++++ UWP/CoreUWP/CoreUWP.vcxproj | 2 + UWP/CoreUWP/CoreUWP.vcxproj.filters | 6 + android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 11 files changed, 843 insertions(+), 769 deletions(-) create mode 100644 Core/HLE/sceNp2.cpp create mode 100644 Core/HLE/sceNp2.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fe807763f..bfa85f981c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1894,6 +1894,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/scePspNpDrm_user.h Core/HLE/sceNp.cpp Core/HLE/sceNp.h + Core/HLE/sceNp2.cpp + Core/HLE/sceNp2.h Core/HLE/scePauth.cpp Core/HLE/scePauth.h Core/HW/SimpleAudioDec.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index bb5688fb30..bdfaea4361 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -535,6 +535,7 @@ + @@ -1087,6 +1088,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 8fc7db771d..3a24903dbc 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1187,6 +1187,9 @@ HW + + HLE\Libraries + @@ -1916,6 +1919,9 @@ HW + + HLE\Libraries + diff --git a/Core/HLE/sceNp.cpp b/Core/HLE/sceNp.cpp index fd6eb1563c..c7328a8ed0 100644 --- a/Core/HLE/sceNp.cpp +++ b/Core/HLE/sceNp.cpp @@ -18,9 +18,6 @@ // This is pretty much a stub implementation. Doesn't actually do anything, just tries to return values // to keep games happy anyway. -#include -#include -#include #include #include "Core/MemMapHelpers.h" #include @@ -32,7 +29,6 @@ bool npAuthInited = false; int npSigninState = NP_SIGNIN_STATUS_NONE; SceNpAuthMemoryStat npAuthMemStat = {}; -SceNpAuthMemoryStat npMatching2MemStat = {}; PSPTimeval npSigninTimestamp{}; // TODO: These should probably be grouped in a struct, since they're used to generate an auth ticket @@ -46,19 +42,12 @@ std::string npOnlineId = "DummyOnlineId"; // SceNpOnlineId struct? std::string npServiceId = ""; // UNO game uses EP2006-NPEH00020_00 std::string npAvatarUrl = "http://DummyAvatarUrl"; // SceNpAvatarUrl struct? -bool npMatching2Inited = false; SceNpCommunicationId npTitleId; std::recursive_mutex npAuthEvtMtx; std::deque npAuthEvents; std::map npAuthHandlers; -// TODO: Moves NpMatching2-related stuff to sceNp2.cpp -std::recursive_mutex npMatching2EvtMtx; -std::deque npMatching2Events; -std::map npMatching2Handlers; -//std::map npMatching2Contexts; - // Tickets data are in big-endian based on captured packets int writeTicketParam(u8* buffer, const u16_be type, const char* data = nullptr, const u16_be size = 0) { @@ -113,20 +102,6 @@ void notifyNpAuthHandlers(u32 id, u32 result, u32 argAddr) { npAuthEvents.push_back({ id, result, argAddr }); } -// serverId: 0 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d (ie. when already joined to a server?) -// unk1~unk5 usually 0, -// unk1: 1st 32-bit of LeaveRoom/etc's Arg2 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d/0x010e -// unk2: 2nd 32-bit of LeaveRoom/etc's Arg2 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d/0x010e -// unk5: 1 on 0x0002/0x0003/0x0005/0x0006/0x0007/0x0101/0x0102/0x0106 -// unk6 (new state?): 8-bit?(masked with 0xff) 0x01 on 0x0001, 0x03 on 0x0002, 0x04 on 0x0003, 0x05 on 0x0004, 0x06 on 0x0005, 0x07 on 0x0006, 0x08 on 0x0007, -// 0x09 on 0x0101, 0x0A on 0x0102, 0x0C on 0x0103, 0x0D on 0x0104, 0x0E on 0x0105, 0x0F on 0x0106, 0x10 on 0x0107, 0x11 on 0x0108, -// 0x12 on 0x0109, 0x13 on 0x010a, 0x14 on 0x010b, 0x15 on 0x010c, 0x16 on 0x010d, 0x17 on 0x010e, 0x18 on 0xa102 -void notifyNpMatching2Handlers(NpMatching2Args &args, u32 ctxId, u32 serverId, u32 cbFuncAddr, u32 cbArgAddr, u32 unk3, u32 unk4, u32 unk5, u8 unk6) { - std::lock_guard npMatching2Guard(npMatching2EvtMtx); - // TODO: separate/map each list per ctxId - npMatching2Events.push_back(args); -} - static int sceNpInit() { ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); @@ -654,517 +629,3 @@ void Register_sceNpCommerce2() RegisterModule("sceNpCommerce2", ARRAY_SIZE(sceNpCommerce2), sceNpCommerce2); } -static int sceNpMatching2Init(int poolSize, int threadPriority, int cpuAffinityMask, int threadStackSize) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d, %d, %d, %d) at %08x", __FUNCTION__, poolSize, threadPriority, cpuAffinityMask, threadStackSize, currentMIPS->pc); - //if (npMatching2Inited) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED); - - npMatching2MemStat.npMemSize = poolSize - 0x20; - npMatching2MemStat.npMaxMemSize = 0x4050; // Dummy maximum foot print - npMatching2MemStat.npFreeMemSize = npMatching2MemStat.npMemSize; - - npMatching2Handlers.clear(); - npMatching2Events.clear(); - npMatching2Inited = true; - return 0; -} - -static int sceNpMatching2Term() -{ - ERROR_LOG(SCENET, "UNIMPL %s() at %08x", __FUNCTION__, currentMIPS->pc); - npMatching2Inited = false; - npMatching2Handlers.clear(); - npMatching2Events.clear(); - - return 0; -} - -static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr, u32 ctxIdPtr, int unknown) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%08x[%s], %08x[%08x], %08x[%d], %d) at %08x", __FUNCTION__, communicationIdPtr, Memory::GetCharPointer(communicationIdPtr), passPhrasePtr, Memory::Read_U32(passPhrasePtr), ctxIdPtr, Memory::Read_U16(ctxIdPtr), unknown, currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (!Memory::IsValidAddress(communicationIdPtr) || !Memory::IsValidAddress(passPhrasePtr) || !Memory::IsValidAddress(ctxIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); - - // FIXME: It seems Context are mapped to TitleID? may return 0x80550C05 or 0x80550C06 when finding an existing context - SceNpCommunicationId* titleid = (SceNpCommunicationId*)Memory::GetCharPointer(communicationIdPtr); - memcpy(npTitleId.data, titleid->data, sizeof(npTitleId)); - - SceNpCommunicationPassphrase* passph = (SceNpCommunicationPassphrase*)Memory::GetCharPointer(passPhrasePtr); - - SceNpId npid{}; - int retval = NpGetNpId(&npid); - if (retval < 0) - return hleLogError(SCENET, retval); - - INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, titleid->data); - INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, npid.handle.data); - std::string datahex; - DataToHexString(npid.opt, sizeof(npid.opt), &datahex); - INFO_LOG(SCENET, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); - datahex.clear(); - DataToHexString(10, 0, passph->data, sizeof(passph->data), &datahex); - INFO_LOG(SCENET, "%s - Passphrase: \n%s", __FUNCTION__, datahex.c_str()); - - // TODO: Allocate & zeroed a memory of 68 bytes where npId (36 bytes) is copied to offset 8, offset 44 = 0x00026808, offset 48 = 0 - - // Returning dummy Id, a 16-bit variable according to JPCSP - // FIXME: It seems ctxId need to be in the range of 1 to 7 to be valid ? - Memory::Write_U16(1, ctxIdPtr); - return 0; -} - -static int sceNpMatching2ContextStart(int ctxId) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - //if (!npMatching2Ctx) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID - - //if (npMatching2Ctx.started) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED); - - // TODO: use sceNpGetUserProfile and check server availability using sceNpService_76867C01 - //npMatching2Ctx.started = true; - Url url("http://static-resource.np.community.playstation.net/np/resource/psp-title/" + std::string(npTitleId.data) + "_00/matching/" + std::string(npTitleId.data) + "_00-matching.xml"); - http::Client client; - http::RequestProgress progress; - if (!client.Resolve(url.Host().c_str(), url.Port())) { - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP failed to resolve %s", url.Resource().c_str()); - } - - client.SetDataTimeout(20.0); - if (client.Connect()) { - char requestHeaders[4096]; - snprintf(requestHeaders, sizeof(requestHeaders), - "User-Agent: PS3Community-agent/1.0.0 libhttp/1.0.0\r\n"); - - DEBUG_LOG(SCENET, "GET URI: %s", url.ToString().c_str()); - http::RequestParams req(url.Resource(), "*/*"); - int err = client.SendRequest("GET", req, requestHeaders, &progress); - if (err < 0) { - client.Disconnect(); - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP GET Error = %d", err); - } - - net::Buffer readbuf; - std::vector responseHeaders; - int code = client.ReadResponseHeaders(&readbuf, responseHeaders, &progress); - if (code != 200) { - client.Disconnect(); - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP Error Code = %d", code); - } - - net::Buffer output; - int res = client.ReadResponseEntity(&readbuf, responseHeaders, &output, &progress); - if (res != 0) { - WARN_LOG(SCENET, "Unable to read HTTP response entity: %d", res); - } - client.Disconnect(); - - std::string entity; - size_t readBytes = output.size(); - output.Take(readBytes, &entity); - - // TODO: Use XML Parser to get the Tag and it's attributes instead of searching for keywords on the string - std::string text; - size_t ofs = entity.find("titleid="); - if (ofs == std::string::npos) - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "titleid not found"); - - ofs += 9; - size_t ofs2 = entity.find('"', ofs); - text = entity.substr(ofs, ofs2-ofs); - INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, text.c_str()); - - int i = 1; - while (true) { - ofs = entity.find("", ++ofs2); - if (ofs == std::string::npos) - return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent host not found"); - - ofs2 = entity.find("pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - //if (!npMatching2Ctx) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID - - //if (!npMatching2Ctx.started) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED); - - //TODO: Stop any in-progress HTTPClient communication used on sceNpMatching2ContextStart - //npMatching2Ctx.started = false; - - return 0; -} - -static int sceNpMatching2DestroyContext(int ctxId) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - //if (!npMatching2Ctx) - // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID - - // Remove callback handler - int handlerID = ctxId - 1; - if (npMatching2Handlers.find(handlerID) != npMatching2Handlers.end()) { - npMatching2Handlers.erase(handlerID); - WARN_LOG(SCENET, "%s: Deleted handler %d", __FUNCTION__, handlerID); - } - else { - ERROR_LOG(SCENET, "%s: Invalid Context ID %d", __FUNCTION__, ctxId); - } - - return 0; -} - -static int sceNpMatching2GetMemoryStat(u32 memStatPtr) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%08x) at %08x", __FUNCTION__, memStatPtr, currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (!Memory::IsValidAddress(memStatPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); - - Memory::WriteStruct(memStatPtr, &npMatching2MemStat); - - return 0; -} - -static int sceNpMatching2RegisterSignalingCallback(int ctxId, u32 callbackFunctionAddr, u32 callbackArgument) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x) at %08x", __FUNCTION__, ctxId, callbackFunctionAddr, callbackArgument, currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (ctxId <= 0) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID); - - int id = ctxId - 1; - if (callbackFunctionAddr != 0) { - bool foundHandler = false; - - struct NpMatching2Handler handler; - memset(&handler, 0, sizeof(handler)); - - handler.entryPoint = callbackFunctionAddr; - handler.argument = callbackArgument; - - for (std::map::iterator it = npMatching2Handlers.begin(); it != npMatching2Handlers.end(); it++) { - if (it->second.entryPoint == handler.entryPoint) { - foundHandler = true; - id = it->first; - break; - } - } - - if (!foundHandler && Memory::IsValidAddress(handler.entryPoint)) { - npMatching2Handlers[id] = handler; - WARN_LOG(SCENET, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, id); - } - else { - ERROR_LOG(SCENET, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); - } - - //u32 dataLength = 4097; - //notifyNpMatching2Handlers(retval, dataLength, handler.argument); - - // callback struct have 57 * u32? where [0]=0, [40]=flags, [55]=callbackFunc, and [56]=callbackArgs? - //hleEnqueueCall(callbackFunctionAddr, 7, (u32*)Memory::GetPointer(callbackArgument), nullptr); // 7 args? since the callback handler is trying to use t2 register - } - return 0; -} - -static int sceNpMatching2GetServerIdListLocal(int ctxId, u32 serverIdsPtr, int maxServerIds) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, ctxId, serverIdsPtr, maxServerIds, currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (!Memory::IsValidAddress(serverIdsPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); - - // Returning dummy Id, a 16-bit variable according to JPCSP - for (int i = 0; i < maxServerIds; i++) - Memory::Write_U16(1234+i, serverIdsPtr+(i*2)); - - return maxServerIds; // dummy value -} - -// Unknown1 = optParam, unknown2 = assignedReqId according to https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.cpp ? -static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1Ptr, u32 unknown2Ptr) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x[%d], %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, serverIdPtr, Memory::Read_U16(serverIdPtr), unknown1Ptr, unknown2Ptr, Memory::Read_U32(unknown2Ptr), currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (!Memory::IsValidAddress(serverIdPtr) || !Memory::IsValidAddress(unknown2Ptr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? - - // Server ID is a 16-bit variable according to JPCSP - int serverId = Memory::Read_U16(serverIdPtr); - - if (serverId == 0) - return hleLogError(SCENET, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? - - // Output to unknown1(infoBuffer)? and unknown2(infoLength or flags)? - // Patapon 3 is using serverId at 09FFF2F4, unknown1 at 09FFF2E4, unknown2 at 09FFF2E0, which mean unknown1's can only fit upto 16-bytes - // Patapon 3 seems to be copying data from unknown1 with a fixed size of 20-bytes? - // input unknown1 struct: based on Fat Princess (US) - // 0000 32-bit function address (callback?) 0x08A08B40 - // 0004 32-bit pointer to a struct? (callback args?) 0x09888158 (contains 32-bit (-1) + 32-bit (1) + 16-bit ctxId(0001) + 32bit 0x06913801? + 16-bit serverId(1234), so on), probably only 2x 32-bit struct? - // 0008 32-bit set to 0 - // 000a 16-bit set to 0 - // - u32 cbFunc = Memory::Read_U32(unknown1Ptr); - u32 cbArg = Memory::Read_U32(unknown1Ptr + 0x04); - - // Notify callback handler - if (Memory::IsValidAddress(cbFunc)) { - // The cbFunc seems to be storing s0~s4(s0 pointing to 0x0996DD58 containing data similar to 0x09888158 above on the 1st 2x 32-bit data, s1 seems to be ctxId, s2~s4=0xdeadbeef) into stack and use a0~t1 (6 args?): - // Arg1(a0) & Arg3(a2) are being masked with 0xffff (16-bit id?) - // This callback tried to load data from address 0x08BD4860+8 (not part of arg? which being set using content of unknown2 not long after returning from sceNpMatching2GetServerInfo, so we may need to give some delay before calling this callback) - // and comparing it with Arg2(a1), repeated by increasing the address 0x08BD4860 by 288 bytes on each loop for 64 times or until it found a matching one. - // When a match is found the callback will process the address further, otherwise exit the callback. - // Matching address struct: (zeroed before calling sceNpMatching2GetServerInfo? and set after returning from sceNpMatching2GetServerInfo?) - // 0000 32-bit func address (another callback?) 0x08A07EF4 - // 0008 32-bit value from unknown2 content, being set not long after returning from sceNpMatching2GetServerInfo - // 000c 32-bit unknown - // 0010 8-bit status to indicate not updated from callback yet? initially 0, set to 1 not long after returning from sceNpMatching2GetServerInfo (along with unknown2 content) - // - // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere - NpMatching2Args args = {}; - args.data[0] = PSP_NP_MATCHING2_EVENT_0001; - args.data[1] = PSP_NP_MATCHING2_STATE_1001; // or size of data? - args.data[2] = serverIdPtr; // serverId or was it pointing to optional data at last arg (ie. args[10] where serverId is stored)? - args.data[3] = unknown1Ptr; - //args.data[4] = a boolean(0/1) related to a u8 value from the struct at args[9] (value XOR 0x04 == 0) - args.data[5] = unknown2Ptr; - args.data[6] = 0; - //args.data[8] = 0 or a pointer to a struct related to context? - //args.data[9] = 0 or a pointer to a struct related to context and matched serverId? - //args.data[10] = serverId; - - notifyNpMatching2Handlers(args, ctxId, serverId, 0, 0, 0, 0, 0, 1); - - Memory::Write_U32(args.data[1], unknown2Ptr); // server status or flags? - } - - // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? - return 0; -} - -static int sceNpMatching2LeaveRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? - - u32 cbFunc = Memory::Read_U32(reqParamPtr); - u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); - - // Notify callback handler - if (Memory::IsValidAddress(cbFunc)) { - // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere - NpMatching2Args args = {}; - args.data[0] = PSP_NP_MATCHING2_EVENT_0103; - args.data[1] = PSP_NP_MATCHING2_STATE_3202; - //args.data[2] = pointer to arg[8], where the 1st 20 bytes copied from (reqParamPtr+0x08), the rest of the struct are zeroed - args.data[3] = optParamPtr; - args.data[4] = 0; - args.data[5] = assignedReqIdPtr; - args.data[6] = 0; - //args.data[8] = an initially zeroed struct of 536 bytes where the 1st 20 bytes were taken from reqParam offset 0x08 - - notifyNpMatching2Handlers(args, ctxId, 0, cbFunc, cbArg, 0, 0, 0, 0x0c); - - Memory::Write_U32(args.data[1], assignedReqIdPtr); - } - - // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? - return 0; -} - -static int sceNpMatching2JoinRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 unknown1, u32 unknown2, u32 assignedReqIdPtr) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? - - // Server ID is a 16-bit variable according to JPCSP - int serverId = Memory::Read_U16(reqParamPtr + 0x06); - - if (serverId == 0) - return hleLogError(SCENET, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? - - u32 cbFunc = Memory::Read_U32(reqParamPtr); - u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); - - // Notify callback handler - if (Memory::IsValidAddress(cbFunc)) { - // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere - NpMatching2Args args = {}; - args.data[0] = PSP_NP_MATCHING2_EVENT_0102; - args.data[1] = PSP_NP_MATCHING2_STATE_1209; - //args.data[2] = pointer to arg[8] (optional data?) - args.data[3] = optParamPtr; - args.data[4] = 0; - args.data[5] = assignedReqIdPtr; - args.data[6] = 0; - // Followed by optional data? - args.data[8] = reqParamPtr; // an initially zeroed struct of 1224 bytes, where the 1st 32bit is set to reqParamPtr - args.data[9] = unknown1; - args.data[10] = unknown2; - - notifyNpMatching2Handlers(args, ctxId, serverId, 0, 0, 0, 0, 1, 0x0a); - - Memory::Write_U32(args.data[1], assignedReqIdPtr); - } - - // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? - return 0; -} - -static int sceNpMatching2SearchRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? - - u32 cbFunc = Memory::Read_U32(reqParamPtr); - u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); - - // Notify callback handler - if (Memory::IsValidAddress(cbFunc)) { - // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere - NpMatching2Args args = {}; - // TODO: Set the correct callback args - - Memory::Write_U32(args.data[1], assignedReqIdPtr); // server status or flags? - } - - return 0; -} - -static int sceNpMatching2SendRoomChatMessage(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) -{ - ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); - if (!npMatching2Inited) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); - - if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) - return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? - - u32 cbFunc = Memory::Read_U32(reqParamPtr); - u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); - - // Notify callback handler - if (Memory::IsValidAddress(cbFunc)) { - // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere - NpMatching2Args args = {}; - args.data[0] = PSP_NP_MATCHING2_EVENT_0107; - args.data[1] = PSP_NP_MATCHING2_STATE_3208; - //args.data[2] = pointer to arg[8] - args.data[3] = optParamPtr; - args.data[4] = 0; - args.data[5] = assignedReqIdPtr; - args.data[6] = 0; - //args.data[8] = reqParamPtr; - - notifyNpMatching2Handlers(args, ctxId, 0, cbFunc, cbArg, 0, 0, 0, 0x10); - - Memory::Write_U32(args.data[1], assignedReqIdPtr); // server status or flags? - } - - // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? - return 0; -} - -const HLEFunction sceNpMatching2[] = { - {0x2E61F6E1, &WrapI_IIII, "sceNpMatching2Init", 'i', "iiii" }, - {0x8BF37D8C, &WrapI_V, "sceNpMatching2Term", 'i', "" }, - {0x5030CC53, &WrapI_UUUI, "sceNpMatching2CreateContext", 'i', "xxxi" }, - {0x190FF903, &WrapI_I, "sceNpMatching2ContextStart", 'i', "i" }, - {0x2B3892FC, &WrapI_I, "sceNpMatching2ContextStop", 'i', "i" }, - {0x3DE70241, &WrapI_I, "sceNpMatching2DestroyContext", 'i', "i" }, - {0x22F38DAF, &WrapI_U, "sceNpMatching2GetMemoryStat", 'i', "x" }, - {0xA3C298D1, &WrapI_IUU, "sceNpMatching2RegisterSignalingCallback", 'i', "ixx" }, - {0xF47342FC, &WrapI_IUI, "sceNpMatching2GetServerIdListLocal", 'i', "ixi" }, - {0x4EE3A8EC, &WrapI_IUUU, "sceNpMatching2GetServerInfo", 'i', "ixxx" }, - {0xC870535A, &WrapI_IUUU, "sceNpMatching2LeaveRoom", 'i', "ixxx" }, - {0xAAD0946A, &WrapI_IUUUUU, "sceNpMatching2JoinRoom", 'i', "ixxxxx" }, - {0x81C13E6D, &WrapI_IUUU, "sceNpMatching2SearchRoom", 'i', "ixxx" }, - {0x55F7837F, &WrapI_IUUU, "sceNpMatching2SendRoomChatMessage", 'i', "ixxx" }, -}; - -void Register_sceNpMatching2() -{ - RegisterModule("sceNpMatching2", ARRAY_SIZE(sceNpMatching2), sceNpMatching2); -} diff --git a/Core/HLE/sceNp.h b/Core/HLE/sceNp.h index 0be9f0ca54..ed2a30646d 100644 --- a/Core/HLE/sceNp.h +++ b/Core/HLE/sceNp.h @@ -17,6 +17,9 @@ #pragma once +#include +#include +#include #include #include "Common/Net/HTTPClient.h" #include "Common/Net/Resolve.h" @@ -159,128 +162,7 @@ #define SCE_NP_COMMUNITY_SERVER_ERROR_UBS_MAINTENANCE 0x805508b3 #define SCE_NP_COMMUNITY_SERVER_ERROR_UNSPECIFIED 0x805508ff -// TODO: Moves NpMatching2-related stuff to sceNp2.h // Based on https://gist.githubusercontent.com/raw/4140449/PS%20Vita (Might be slightly different with PSP?) -#define SCE_NP_MATCHING2_ERROR_OUT_OF_MEMORY 0x80550c01 -#define SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED 0x80550c02 -#define SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED 0x80550c03 -#define SCE_NP_MATCHING2_ERROR_CONTEXT_MAX 0x80550c04 // might be "Invalid Argument" on PSP? -#define SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_EXISTS 0x80550c05 // might be "Context Max/Context Id higher than 7" on PSP? -#define SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND 0x80550c06 -#define SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED 0x80550c07 -#define SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED 0x80550c08 -#define SCE_NP_MATCHING2_ERROR_SERVER_NOT_FOUND 0x80550c09 -#define SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT 0x80550c0a -#define SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID 0x80550c0b -#define SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID 0x80550c0c -#define SCE_NP_MATCHING2_ERROR_INVALID_LOBBY_ID 0x80550c0e -#define SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID 0x80550c0f -#define SCE_NP_MATCHING2_ERROR_INVALID_MEMBER_ID 0x80550c10 -#define SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_ID 0x80550c11 -#define SCE_NP_MATCHING2_ERROR_INVALID_CASTTYPE 0x80550c12 -#define SCE_NP_MATCHING2_ERROR_INVALID_SORT_METHOD 0x80550c13 -#define SCE_NP_MATCHING2_ERROR_INVALID_MAX_SLOT 0x80550c14 -#define SCE_NP_MATCHING2_ERROR_INVALID_OPT_SIZE 0x80550c15 -#define SCE_NP_MATCHING2_ERROR_INVALID_MATCHING_SPACE 0x80550c16 -#define SCE_NP_MATCHING2_ERROR_INVALID_BLOCK_KICK_FLAG 0x80550c18 -#define SCE_NP_MATCHING2_ERROR_INVALID_MESSAGE_TARGET 0x80550c19 -#define SCE_NP_MATCHING2_ERROR_RANGE_FILTER_MAX 0x80550c1a -#define SCE_NP_MATCHING2_ERROR_INVALID_ALIGNMENT 0x80550c1e -#define SCE_NP_MATCHING2_ERROR_CONNECTION_CLOSED_BY_SERVER 0x80550c22 -#define SCE_NP_MATCHING2_ERROR_SSL_VERIFY_FAILED 0x80550c23 -#define SCE_NP_MATCHING2_ERROR_SSL_HANDSHAKE 0x80550c24 -#define SCE_NP_MATCHING2_ERROR_SSL_SEND 0x80550c25 -#define SCE_NP_MATCHING2_ERROR_SSL_RECV 0x80550c26 -#define SCE_NP_MATCHING2_ERROR_JOINED_SESSION_MAX 0x80550c27 -#define SCE_NP_MATCHING2_ERROR_ALREADY_JOINED 0x80550c28 -#define SCE_NP_MATCHING2_ERROR_INVALID_SESSION_TYPE 0x80550c29 -#define SCE_NP_MATCHING2_ERROR_NP_SIGNED_OUT 0x80550c2b -#define SCE_NP_MATCHING2_ERROR_BUSY 0x80550c2c -#define SCE_NP_MATCHING2_ERROR_SERVER_NOT_AVAILABLE 0x80550c2d -#define SCE_NP_MATCHING2_ERROR_NOT_ALLOWED 0x80550c2e -#define SCE_NP_MATCHING2_ERROR_ABORTED 0x80550c2f -#define SCE_NP_MATCHING2_ERROR_REQUEST_NOT_FOUND 0x80550c30 -#define SCE_NP_MATCHING2_ERROR_SESSION_DESTROYED 0x80550c31 -#define SCE_NP_MATCHING2_ERROR_CONTEXT_STOPPED 0x80550c32 -#define SCE_NP_MATCHING2_ERROR_INVALID_REQUEST_PARAMETER 0x80550c33 -#define SCE_NP_MATCHING2_ERROR_NOT_NP_SIGN_IN 0x80550c34 -#define SCE_NP_MATCHING2_ERROR_ROOM_NOT_FOUND 0x80550c35 -#define SCE_NP_MATCHING2_ERROR_ROOM_MEMBER_NOT_FOUND 0x80550c36 -#define SCE_NP_MATCHING2_ERROR_LOBBY_NOT_FOUND 0x80550c37 -#define SCE_NP_MATCHING2_ERROR_LOBBY_MEMBER_NOT_FOUND 0x80550c38 -#define SCE_NP_MATCHING2_ERROR_KEEPALIVE_TIMEOUT 0x80550c3a -#define SCE_NP_MATCHING2_ERROR_TIMEOUT_TOO_SHORT 0x80550c3b -#define SCE_NP_MATCHING2_ERROR_TIMEDOUT 0x80550c3c -#define SCE_NP_MATCHING2_ERROR_INVALID_SLOTGROUP 0x80550c3d -#define SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_SIZE 0x80550c3e -#define SCE_NP_MATCHING2_ERROR_CANNOT_ABORT 0x80550c3f -#define SCE_NP_MATCHING2_ERROR_SESSION_NOT_FOUND 0x80550c40 - -#define SCE_NP_MATCHING2_SERVER_ERROR_BAD_REQUEST 0x80550d01 -#define SCE_NP_MATCHING2_SERVER_ERROR_SERVICE_UNAVAILABLE 0x80550d02 -#define SCE_NP_MATCHING2_SERVER_ERROR_BUSY 0x80550d03 -#define SCE_NP_MATCHING2_SERVER_ERROR_END_OF_SERVICE 0x80550d04 -#define SCE_NP_MATCHING2_SERVER_ERROR_INTERNAL_SERVER_ERROR 0x80550d05 -#define SCE_NP_MATCHING2_SERVER_ERROR_PLAYER_BANNED 0x80550d06 -#define SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN 0x80550d07 -#define SCE_NP_MATCHING2_SERVER_ERROR_BLOCKED 0x80550d08 -#define SCE_NP_MATCHING2_SERVER_ERROR_UNSUPPORTED_NP_ENV 0x80550d09 -#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_TICKET 0x80550d0a -#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_SIGNATURE 0x80550d0b -#define SCE_NP_MATCHING2_SERVER_ERROR_EXPIRED_TICKET 0x80550d0c -#define SCE_NP_MATCHING2_SERVER_ERROR_ENTITLEMENT_REQUIRED 0x80550d0d -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_CONTEXT 0x80550d0e -#define SCE_NP_MATCHING2_SERVER_ERROR_CLOSED 0x80550d0f -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_TITLE 0x80550d10 -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_WORLD 0x80550d11 -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_LOBBY 0x80550d12 -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM 0x80550d13 -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_LOBBY_INSTANCE 0x80550d14 -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM_INSTANCE 0x80550d15 -#define SCE_NP_MATCHING2_SERVER_ERROR_PASSWORD_MISMATCH 0x80550d17 -#define SCE_NP_MATCHING2_SERVER_ERROR_LOBBY_FULL 0x80550d18 -#define SCE_NP_MATCHING2_SERVER_ERROR_ROOM_FULL 0x80550d19 -#define SCE_NP_MATCHING2_SERVER_ERROR_GROUP_FULL 0x80550d1b -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER 0x80550d1c -#define SCE_NP_MATCHING2_SERVER_ERROR_TITLE_PASSPHRASE_MISMATCH 0x80550d1e -#define SCE_NP_MATCHING2_SERVER_ERROR_CONSOLE_BANNED 0x80550d28 -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_ROOMGROUP 0x80550d29 -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_GROUP 0x80550d2a -#define SCE_NP_MATCHING2_SERVER_ERROR_NO_PASSWORD 0x80550d2b -#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_GROUP_SLOT_NUM 0x80550d2c -#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_PASSWORD_SLOT_MASK 0x80550d2d -#define SCE_NP_MATCHING2_SERVER_ERROR_DUPLICATE_GROUP_LABEL 0x80550d2e -#define SCE_NP_MATCHING2_SERVER_ERROR_REQUEST_OVERFLOW 0x80550d2f -#define SCE_NP_MATCHING2_SERVER_ERROR_ALREADY_JOINED 0x80550d30 -#define SCE_NP_MATCHING2_SERVER_ERROR_NAT_TYPE_MISMATCH 0x80550d31 -#define SCE_NP_MATCHING2_SERVER_ERROR_ROOM_INCONSISTENCY 0x80550d32 - -#define SCE_NP_MATCHING2_SIGNALING_ERROR_NOT_INITIALIZED 0x80550e01 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_ALREADY_INITIALIZED 0x80550e02 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_OUT_OF_MEMORY 0x80550e03 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTXID_NOT_AVAILABLE 0x80550e04 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTX_NOT_FOUND 0x80550e05 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_REQID_NOT_AVAILABLE 0x80550e06 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_REQ_NOT_FOUND 0x80550e07 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_PARSER_CREATE_FAILED 0x80550e08 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_PARSER_FAILED 0x80550e09 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_INVALID_NAMESPACE 0x80550e0a -#define SCE_NP_MATCHING2_SIGNALING_ERROR_NETINFO_NOT_AVAILABLE 0x80550e0b -#define SCE_NP_MATCHING2_SIGNALING_ERROR_PEER_NOT_RESPONDING 0x80550e0c -#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONNID_NOT_AVAILABLE 0x80550e0d -#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONN_NOT_FOUND 0x80550e0e -#define SCE_NP_MATCHING2_SIGNALING_ERROR_PEER_UNREACHABLE 0x80550e0f -#define SCE_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_PEER 0x80550e10 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_TIMEOUT 0x80550e11 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTX_MAX 0x80550e12 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_RESULT_NOT_FOUND 0x80550e13 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONN_IN_PROGRESS 0x80550e14 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_INVALID_ARGUMENT 0x80550e15 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_OWN_NP_ID 0x80550e16 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_TOO_MANY_CONN 0x80550e17 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_MYSELF 0x80550e18 -#define SCE_NP_MATCHING2_SIGNALING_ERROR_MATCHING2_PEER_NOT_FOUND 0x80550e19 - #define SCE_NP_TROPHY_ERROR_UNKNOWN 0x80551600 #define SCE_NP_TROPHY_ERROR_NOT_INITIALIZED 0x80551601 #define SCE_NP_TROPHY_ERROR_ALREADY_INITIALIZED 0x80551602 @@ -526,114 +408,6 @@ struct SceNpAuthMemoryStat { int npFreeMemSize; // Free memory available to use by the NP utility. }; - -// Based on https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.h (Just as reference, might be slightly different than PSP) -// Event of request functions -enum PS3Matching2RequestEvent -{ - SCE_NP_MATCHING2_REQUEST_EVENT_GetServerInfo = 0x0001, - SCE_NP_MATCHING2_REQUEST_EVENT_GetWorldInfoList = 0x0002, - SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataExternalList = 0x0003, - SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal = 0x0004, - SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList = 0x0005, - SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyInfoList = 0x0006, - SCE_NP_MATCHING2_REQUEST_EVENT_SetUserInfo = 0x0007, - SCE_NP_MATCHING2_REQUEST_EVENT_GetUserInfoList = 0x0008, - SCE_NP_MATCHING2_REQUEST_EVENT_CreateServerContext = 0x0009, - SCE_NP_MATCHING2_REQUEST_EVENT_DeleteServerContext = 0x000a, - SCE_NP_MATCHING2_REQUEST_EVENT_CreateJoinRoom = 0x0101, - SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom = 0x0102, - SCE_NP_MATCHING2_REQUEST_EVENT_LeaveRoom = 0x0103, - SCE_NP_MATCHING2_REQUEST_EVENT_GrantRoomOwner = 0x0104, - SCE_NP_MATCHING2_REQUEST_EVENT_KickoutRoomMember = 0x0105, - SCE_NP_MATCHING2_REQUEST_EVENT_SearchRoom = 0x0106, - SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomChatMessage = 0x0107, - SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomMessage = 0x0108, - SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataInternal = 0x0109, - SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataInternal = 0x010a, - SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomMemberDataInternal = 0x010b, - SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataInternal = 0x010c, - SCE_NP_MATCHING2_REQUEST_EVENT_SetSignalingOptParam = 0x010d, - SCE_NP_MATCHING2_REQUEST_EVENT_JoinLobby = 0x0201, - SCE_NP_MATCHING2_REQUEST_EVENT_LeaveLobby = 0x0202, - SCE_NP_MATCHING2_REQUEST_EVENT_SendLobbyChatMessage = 0x0203, - SCE_NP_MATCHING2_REQUEST_EVENT_SendLobbyInvitation = 0x0204, - SCE_NP_MATCHING2_REQUEST_EVENT_SetLobbyMemberDataInternal = 0x0205, - SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyMemberDataInternal = 0x0206, - SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyMemberDataInternalList = 0x0207, - SCE_NP_MATCHING2_REQUEST_EVENT_SignalingGetPingInfo = 0x0e01, -}; - -// Based on decompiled np_matching2.prx, commented with syscalls where the event id is being used -#define PSP_NP_MATCHING2_EVENT_0001 0x0001 // GetServerInfo -#define PSP_NP_MATCHING2_EVENT_0002 0x0002 // GetWorldInfoList -#define PSP_NP_MATCHING2_EVENT_0003 0x0003 // SetUserInfo -#define PSP_NP_MATCHING2_EVENT_0004 0x0004 // GetUserInfoList -#define PSP_NP_MATCHING2_EVENT_0005 0x0005 // GetRoomMemberDataExternalList -#define PSP_NP_MATCHING2_EVENT_0006 0x0006 // SetRoomDataExternal -#define PSP_NP_MATCHING2_EVENT_0007 0x0007 // GetRoomDataExternalList - -#define PSP_NP_MATCHING2_EVENT_0101 0x0101 // CreateJoinRoom -#define PSP_NP_MATCHING2_EVENT_0102 0x0102 // JoinRoom -#define PSP_NP_MATCHING2_EVENT_0103 0x0103 // LeaveRoom -#define PSP_NP_MATCHING2_EVENT_0104 0x0104 // GrantRoomOwner -#define PSP_NP_MATCHING2_EVENT_0105 0x0105 // KickoutRoomMember -#define PSP_NP_MATCHING2_EVENT_0106 0x0106 // SearchRoom -#define PSP_NP_MATCHING2_EVENT_0107 0x0107 // SendRoomChatMessage -#define PSP_NP_MATCHING2_EVENT_0108 0x0108 // SendRoomMessage, also used on various places (internal function) -#define PSP_NP_MATCHING2_EVENT_0109 0x0109 // SetRoomDataInternal -#define PSP_NP_MATCHING2_EVENT_010A 0x010A // GetRoomDataInternal -#define PSP_NP_MATCHING2_EVENT_010B 0x010B // SetRoomMemberDataInternal -#define PSP_NP_MATCHING2_EVENT_010C 0x010C // GetRoomMemberDataInternal -#define PSP_NP_MATCHING2_EVENT_010D 0x010D // GetRoomMemberDataInternalList -#define PSP_NP_MATCHING2_EVENT_010E 0x010E // SetSignalingOptParam - -#define PSP_NP_MATCHING2_EVENT_A102 0xA102 // Used on various places (internal function) - -// Either this is an ID, state/status, flags, or might be size of data? -#define PSP_NP_MATCHING2_STATE_1001 0x1001 -#define PSP_NP_MATCHING2_STATE_1006 0x1006 -#define PSP_NP_MATCHING2_STATE_1007 0x1007 -#define PSP_NP_MATCHING2_STATE_1008 0x1008 - -#define PSP_NP_MATCHING2_STATE_1200 0x1200 -#define PSP_NP_MATCHING2_STATE_1206 0x1206 -#define PSP_NP_MATCHING2_STATE_1207 0x1207 -#define PSP_NP_MATCHING2_STATE_1208 0x1208 -#define PSP_NP_MATCHING2_STATE_1209 0x1209 -#define PSP_NP_MATCHING2_STATE_120B 0x120B -#define PSP_NP_MATCHING2_STATE_120C 0x120C - -#define PSP_NP_MATCHING2_STATE_3202 0x3202 -#define PSP_NP_MATCHING2_STATE_3203 0x3203 -#define PSP_NP_MATCHING2_STATE_3204 0x3204 -#define PSP_NP_MATCHING2_STATE_3205 0x3205 -#define PSP_NP_MATCHING2_STATE_3206 0x3206 -#define PSP_NP_MATCHING2_STATE_3207 0x3207 -#define PSP_NP_MATCHING2_STATE_3208 0x3208 -#define PSP_NP_MATCHING2_STATE_320A 0x320A -#define PSP_NP_MATCHING2_STATE_3210 0x3210 -#define PSP_NP_MATCHING2_STATE_3211 0x3211 - -#define PSP_NP_MATCHING2_MAX_CONTEXTID 7; - -struct NpMatching2Handler { - u32 entryPoint; - u32 argument; -}; - -// Arg1 and Arg2 seems to be a pair and predefined: 0x0001 with 0x1001, 0x0002 with 0x1008, 0x0003 with 0x1006, 0x0004 with 0x1007, -// 0x0005 with 0x1206, 0x0006 with 0x1207, 0x0007 with 0x1208, 0x0101 with 0x1209, 0x0102 with 0x1209, 0x0103 with 0x3202, -// 0x0104 with 0x3210, 0x0105 with 0x3211, 0x0106 with 2 possibilities (0x1200 and 0x120c), 0x0107 with 0x3208, 0x0108 with 0x320a, -// 0x0109 with 0x3204, 0x010a with 0x3205, 0x010b with 0x3206, 0x010c with 0x3207, 0x010d with 0x3203, 0x010e with 0x3204, -// 0xa102 with 0x120b. -// Arg5 seems to be boolean (0/1), mostly 0, conditional when Arg1=0x0001 -// Arg7 seems to be integer/state? (0..2), mostly 0, conditional when Arg1=0x0108 (0 on SendRoomMessage, 2 on others), 1 when Arg1=0xa102 -struct NpMatching2Args { - u32_le data[11]; // 7 elements (excluding optional data)? or may be 11 elements (including optional data)? - // May be followed by optional data? since these Args usually created on the stack -}; - #pragma pack(pop) @@ -675,4 +449,3 @@ void Register_sceNp(); void Register_sceNpService(); void Register_sceNpAuth(); void Register_sceNpCommerce2(); -void Register_sceNpMatching2(); diff --git a/Core/HLE/sceNp2.cpp b/Core/HLE/sceNp2.cpp new file mode 100644 index 0000000000..588471ba37 --- /dev/null +++ b/Core/HLE/sceNp2.cpp @@ -0,0 +1,566 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +// This is pretty much a stub implementation. Doesn't actually do anything, just tries to return values +// to keep games happy anyway. + +#include +#include "Core/MemMapHelpers.h" +#include +#include "Core/HLE/HLE.h" +#include "Core/HLE/FunctionWrappers.h" +#include "Core/HLE/sceNp.h" +#include "Core/HLE/sceNp2.h" + + +bool npMatching2Inited = false; +SceNpAuthMemoryStat npMatching2MemStat = {}; + +std::recursive_mutex npMatching2EvtMtx; +std::deque npMatching2Events; +std::map npMatching2Handlers; +//std::map npMatching2Contexts; + + +// serverId: 0 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d (ie. when already joined to a server?) +// unk1~unk5 usually 0, +// unk1: 1st 32-bit of LeaveRoom/etc's Arg2 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d/0x010e +// unk2: 2nd 32-bit of LeaveRoom/etc's Arg2 on 0x0103/0x0104/0x0105/0x0107/0x0108/0x0109/0x010a/0x010b/0x010c/0x010d/0x010e +// unk5: 1 on 0x0002/0x0003/0x0005/0x0006/0x0007/0x0101/0x0102/0x0106 +// unk6 (new state?): 8-bit?(masked with 0xff) 0x01 on 0x0001, 0x03 on 0x0002, 0x04 on 0x0003, 0x05 on 0x0004, 0x06 on 0x0005, 0x07 on 0x0006, 0x08 on 0x0007, +// 0x09 on 0x0101, 0x0A on 0x0102, 0x0C on 0x0103, 0x0D on 0x0104, 0x0E on 0x0105, 0x0F on 0x0106, 0x10 on 0x0107, 0x11 on 0x0108, +// 0x12 on 0x0109, 0x13 on 0x010a, 0x14 on 0x010b, 0x15 on 0x010c, 0x16 on 0x010d, 0x17 on 0x010e, 0x18 on 0xa102 +void notifyNpMatching2Handlers(NpMatching2Args &args, u32 ctxId, u32 serverId, u32 cbFuncAddr, u32 cbArgAddr, u32 unk3, u32 unk4, u32 unk5, u8 unk6) { + std::lock_guard npMatching2Guard(npMatching2EvtMtx); + // TODO: separate/map each list per ctxId + npMatching2Events.push_back(args); +} + +static int sceNpMatching2Init(int poolSize, int threadPriority, int cpuAffinityMask, int threadStackSize) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %d, %d, %d) at %08x", __FUNCTION__, poolSize, threadPriority, cpuAffinityMask, threadStackSize, currentMIPS->pc); + //if (npMatching2Inited) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED); + + npMatching2MemStat.npMemSize = poolSize - 0x20; + npMatching2MemStat.npMaxMemSize = 0x4050; // Dummy maximum foot print + npMatching2MemStat.npFreeMemSize = npMatching2MemStat.npMemSize; + + npMatching2Handlers.clear(); + npMatching2Events.clear(); + npMatching2Inited = true; + return 0; +} + +static int sceNpMatching2Term() +{ + ERROR_LOG(SCENET, "UNIMPL %s() at %08x", __FUNCTION__, currentMIPS->pc); + npMatching2Inited = false; + npMatching2Handlers.clear(); + npMatching2Events.clear(); + + return 0; +} + +static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr, u32 ctxIdPtr, int unknown) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%08x[%s], %08x[%08x], %08x[%d], %d) at %08x", __FUNCTION__, communicationIdPtr, Memory::GetCharPointer(communicationIdPtr), passPhrasePtr, Memory::Read_U32(passPhrasePtr), ctxIdPtr, Memory::Read_U16(ctxIdPtr), unknown, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(communicationIdPtr) || !Memory::IsValidAddress(passPhrasePtr) || !Memory::IsValidAddress(ctxIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); + + // FIXME: It seems Context are mapped to TitleID? may return 0x80550C05 or 0x80550C06 when finding an existing context + SceNpCommunicationId* titleid = (SceNpCommunicationId*)Memory::GetCharPointer(communicationIdPtr); + memcpy(npTitleId.data, titleid->data, sizeof(npTitleId)); + + SceNpCommunicationPassphrase* passph = (SceNpCommunicationPassphrase*)Memory::GetCharPointer(passPhrasePtr); + + SceNpId npid{}; + int retval = NpGetNpId(&npid); + if (retval < 0) + return hleLogError(SCENET, retval); + + INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, titleid->data); + INFO_LOG(SCENET, "%s - Online ID: %s", __FUNCTION__, npid.handle.data); + std::string datahex; + DataToHexString(npid.opt, sizeof(npid.opt), &datahex); + INFO_LOG(SCENET, "%s - Options?: %s", __FUNCTION__, datahex.c_str()); + datahex.clear(); + DataToHexString(10, 0, passph->data, sizeof(passph->data), &datahex); + INFO_LOG(SCENET, "%s - Passphrase: \n%s", __FUNCTION__, datahex.c_str()); + + // TODO: Allocate & zeroed a memory of 68 bytes where npId (36 bytes) is copied to offset 8, offset 44 = 0x00026808, offset 48 = 0 + + // Returning dummy Id, a 16-bit variable according to JPCSP + // FIXME: It seems ctxId need to be in the range of 1 to 7 to be valid ? + Memory::Write_U16(1, ctxIdPtr); + return 0; +} + +static int sceNpMatching2ContextStart(int ctxId) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + //if (!npMatching2Ctx) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + + //if (npMatching2Ctx.started) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED); + + // TODO: use sceNpGetUserProfile and check server availability using sceNpService_76867C01 + //npMatching2Ctx.started = true; + Url url("http://static-resource.np.community.playstation.net/np/resource/psp-title/" + std::string(npTitleId.data) + "_00/matching/" + std::string(npTitleId.data) + "_00-matching.xml"); + http::Client client; + http::RequestProgress progress; + if (!client.Resolve(url.Host().c_str(), url.Port())) { + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP failed to resolve %s", url.Resource().c_str()); + } + + client.SetDataTimeout(20.0); + if (client.Connect()) { + char requestHeaders[4096]; + snprintf(requestHeaders, sizeof(requestHeaders), + "User-Agent: PS3Community-agent/1.0.0 libhttp/1.0.0\r\n"); + + DEBUG_LOG(SCENET, "GET URI: %s", url.ToString().c_str()); + http::RequestParams req(url.Resource(), "*/*"); + int err = client.SendRequest("GET", req, requestHeaders, &progress); + if (err < 0) { + client.Disconnect(); + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP GET Error = %d", err); + } + + net::Buffer readbuf; + std::vector responseHeaders; + int code = client.ReadResponseHeaders(&readbuf, responseHeaders, &progress); + if (code != 200) { + client.Disconnect(); + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP Error Code = %d", code); + } + + net::Buffer output; + int res = client.ReadResponseEntity(&readbuf, responseHeaders, &output, &progress); + if (res != 0) { + WARN_LOG(SCENET, "Unable to read HTTP response entity: %d", res); + } + client.Disconnect(); + + std::string entity; + size_t readBytes = output.size(); + output.Take(readBytes, &entity); + + // TODO: Use XML Parser to get the Tag and it's attributes instead of searching for keywords on the string + std::string text; + size_t ofs = entity.find("titleid="); + if (ofs == std::string::npos) + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "titleid not found"); + + ofs += 9; + size_t ofs2 = entity.find('"', ofs); + text = entity.substr(ofs, ofs2-ofs); + INFO_LOG(SCENET, "%s - Title ID: %s", __FUNCTION__, text.c_str()); + + int i = 1; + while (true) { + ofs = entity.find("", ++ofs2); + if (ofs == std::string::npos) + return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent host not found"); + + ofs2 = entity.find("pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + //if (!npMatching2Ctx) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + + //if (!npMatching2Ctx.started) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED); + + //TODO: Stop any in-progress HTTPClient communication used on sceNpMatching2ContextStart + //npMatching2Ctx.started = false; + + return 0; +} + +static int sceNpMatching2DestroyContext(int ctxId) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d) at %08x", __FUNCTION__, ctxId, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + //if (!npMatching2Ctx) + // return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND); //SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID + + // Remove callback handler + int handlerID = ctxId - 1; + if (npMatching2Handlers.find(handlerID) != npMatching2Handlers.end()) { + npMatching2Handlers.erase(handlerID); + WARN_LOG(SCENET, "%s: Deleted handler %d", __FUNCTION__, handlerID); + } + else { + ERROR_LOG(SCENET, "%s: Invalid Context ID %d", __FUNCTION__, ctxId); + } + + return 0; +} + +static int sceNpMatching2GetMemoryStat(u32 memStatPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%08x) at %08x", __FUNCTION__, memStatPtr, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(memStatPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); + + Memory::WriteStruct(memStatPtr, &npMatching2MemStat); + + return 0; +} + +static int sceNpMatching2RegisterSignalingCallback(int ctxId, u32 callbackFunctionAddr, u32 callbackArgument) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x) at %08x", __FUNCTION__, ctxId, callbackFunctionAddr, callbackArgument, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (ctxId <= 0) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID); + + int id = ctxId - 1; + if (callbackFunctionAddr != 0) { + bool foundHandler = false; + + struct NpMatching2Handler handler; + memset(&handler, 0, sizeof(handler)); + + handler.entryPoint = callbackFunctionAddr; + handler.argument = callbackArgument; + + for (std::map::iterator it = npMatching2Handlers.begin(); it != npMatching2Handlers.end(); it++) { + if (it->second.entryPoint == handler.entryPoint) { + foundHandler = true; + id = it->first; + break; + } + } + + if (!foundHandler && Memory::IsValidAddress(handler.entryPoint)) { + npMatching2Handlers[id] = handler; + WARN_LOG(SCENET, "%s - Added handler(%08x, %08x) : %d", __FUNCTION__, handler.entryPoint, handler.argument, id); + } + else { + ERROR_LOG(SCENET, "%s - Same handler(%08x, %08x) already exists", __FUNCTION__, handler.entryPoint, handler.argument); + } + + //u32 dataLength = 4097; + //notifyNpMatching2Handlers(retval, dataLength, handler.argument); + + // callback struct have 57 * u32? where [0]=0, [40]=flags, [55]=callbackFunc, and [56]=callbackArgs? + //hleEnqueueCall(callbackFunctionAddr, 7, (u32*)Memory::GetPointer(callbackArgument), nullptr); // 7 args? since the callback handler is trying to use t2 register + } + return 0; +} + +static int sceNpMatching2GetServerIdListLocal(int ctxId, u32 serverIdsPtr, int maxServerIds) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %d) at %08x", __FUNCTION__, ctxId, serverIdsPtr, maxServerIds, currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(serverIdsPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT); + + // Returning dummy Id, a 16-bit variable according to JPCSP + for (int i = 0; i < maxServerIds; i++) + Memory::Write_U16(1234+i, serverIdsPtr+(i*2)); + + return maxServerIds; // dummy value +} + +// Unknown1 = optParam, unknown2 = assignedReqId according to https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.cpp ? +static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1Ptr, u32 unknown2Ptr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x[%d], %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, serverIdPtr, Memory::Read_U16(serverIdPtr), unknown1Ptr, unknown2Ptr, Memory::Read_U32(unknown2Ptr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(serverIdPtr) || !Memory::IsValidAddress(unknown2Ptr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + // Server ID is a 16-bit variable according to JPCSP + int serverId = Memory::Read_U16(serverIdPtr); + + if (serverId == 0) + return hleLogError(SCENET, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? + + // Output to unknown1(infoBuffer)? and unknown2(infoLength or flags)? + // Patapon 3 is using serverId at 09FFF2F4, unknown1 at 09FFF2E4, unknown2 at 09FFF2E0, which mean unknown1's can only fit upto 16-bytes + // Patapon 3 seems to be copying data from unknown1 with a fixed size of 20-bytes? + // input unknown1 struct: based on Fat Princess (US) + // 0000 32-bit function address (callback?) 0x08A08B40 + // 0004 32-bit pointer to a struct? (callback args?) 0x09888158 (contains 32-bit (-1) + 32-bit (1) + 16-bit ctxId(0001) + 32bit 0x06913801? + 16-bit serverId(1234), so on), probably only 2x 32-bit struct? + // 0008 32-bit set to 0 + // 000a 16-bit set to 0 + // + u32 cbFunc = Memory::Read_U32(unknown1Ptr); + u32 cbArg = Memory::Read_U32(unknown1Ptr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // The cbFunc seems to be storing s0~s4(s0 pointing to 0x0996DD58 containing data similar to 0x09888158 above on the 1st 2x 32-bit data, s1 seems to be ctxId, s2~s4=0xdeadbeef) into stack and use a0~t1 (6 args?): + // Arg1(a0) & Arg3(a2) are being masked with 0xffff (16-bit id?) + // This callback tried to load data from address 0x08BD4860+8 (not part of arg? which being set using content of unknown2 not long after returning from sceNpMatching2GetServerInfo, so we may need to give some delay before calling this callback) + // and comparing it with Arg2(a1), repeated by increasing the address 0x08BD4860 by 288 bytes on each loop for 64 times or until it found a matching one. + // When a match is found the callback will process the address further, otherwise exit the callback. + // Matching address struct: (zeroed before calling sceNpMatching2GetServerInfo? and set after returning from sceNpMatching2GetServerInfo?) + // 0000 32-bit func address (another callback?) 0x08A07EF4 + // 0008 32-bit value from unknown2 content, being set not long after returning from sceNpMatching2GetServerInfo + // 000c 32-bit unknown + // 0010 8-bit status to indicate not updated from callback yet? initially 0, set to 1 not long after returning from sceNpMatching2GetServerInfo (along with unknown2 content) + // + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + args.data[0] = PSP_NP_MATCHING2_EVENT_0001; + args.data[1] = PSP_NP_MATCHING2_STATE_1001; // or size of data? + args.data[2] = serverIdPtr; // serverId or was it pointing to optional data at last arg (ie. args[10] where serverId is stored)? + args.data[3] = unknown1Ptr; + //args.data[4] = a boolean(0/1) related to a u8 value from the struct at args[9] (value XOR 0x04 == 0) + args.data[5] = unknown2Ptr; + args.data[6] = 0; + //args.data[8] = 0 or a pointer to a struct related to context? + //args.data[9] = 0 or a pointer to a struct related to context and matched serverId? + //args.data[10] = serverId; + + notifyNpMatching2Handlers(args, ctxId, serverId, 0, 0, 0, 0, 0, 1); + + Memory::Write_U32(args.data[1], unknown2Ptr); // server status or flags? + } + + // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? + return 0; +} + +static int sceNpMatching2LeaveRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + u32 cbFunc = Memory::Read_U32(reqParamPtr); + u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + args.data[0] = PSP_NP_MATCHING2_EVENT_0103; + args.data[1] = PSP_NP_MATCHING2_STATE_3202; + //args.data[2] = pointer to arg[8], where the 1st 20 bytes copied from (reqParamPtr+0x08), the rest of the struct are zeroed + args.data[3] = optParamPtr; + args.data[4] = 0; + args.data[5] = assignedReqIdPtr; + args.data[6] = 0; + //args.data[8] = an initially zeroed struct of 536 bytes where the 1st 20 bytes were taken from reqParam offset 0x08 + + notifyNpMatching2Handlers(args, ctxId, 0, cbFunc, cbArg, 0, 0, 0, 0x0c); + + Memory::Write_U32(args.data[1], assignedReqIdPtr); + } + + // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? + return 0; +} + +static int sceNpMatching2JoinRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 unknown1, u32 unknown2, u32 assignedReqIdPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + // Server ID is a 16-bit variable according to JPCSP + int serverId = Memory::Read_U16(reqParamPtr + 0x06); + + if (serverId == 0) + return hleLogError(SCENET, 0x80550CBF); // Should be SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID ? + + u32 cbFunc = Memory::Read_U32(reqParamPtr); + u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + args.data[0] = PSP_NP_MATCHING2_EVENT_0102; + args.data[1] = PSP_NP_MATCHING2_STATE_1209; + //args.data[2] = pointer to arg[8] (optional data?) + args.data[3] = optParamPtr; + args.data[4] = 0; + args.data[5] = assignedReqIdPtr; + args.data[6] = 0; + // Followed by optional data? + args.data[8] = reqParamPtr; // an initially zeroed struct of 1224 bytes, where the 1st 32bit is set to reqParamPtr + args.data[9] = unknown1; + args.data[10] = unknown2; + + notifyNpMatching2Handlers(args, ctxId, serverId, 0, 0, 0, 0, 1, 0x0a); + + Memory::Write_U32(args.data[1], assignedReqIdPtr); + } + + // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? + return 0; +} + +static int sceNpMatching2SearchRoom(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + u32 cbFunc = Memory::Read_U32(reqParamPtr); + u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + // TODO: Set the correct callback args + + Memory::Write_U32(args.data[1], assignedReqIdPtr); // server status or flags? + } + + return 0; +} + +static int sceNpMatching2SendRoomChatMessage(int ctxId, u32 reqParamPtr, u32 optParamPtr, u32 assignedReqIdPtr) +{ + ERROR_LOG(SCENET, "UNIMPL %s(%d, %08x, %08x, %08x[%08x]) at %08x", __FUNCTION__, ctxId, reqParamPtr, optParamPtr, assignedReqIdPtr, Memory::Read_U32(assignedReqIdPtr), currentMIPS->pc); + if (!npMatching2Inited) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED); + + if (!Memory::IsValidAddress(reqParamPtr) || !Memory::IsValidAddress(assignedReqIdPtr)) + return hleLogError(SCENET, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ? + + u32 cbFunc = Memory::Read_U32(reqParamPtr); + u32 cbArg = Memory::Read_U32(reqParamPtr + 0x04); + + // Notify callback handler + if (Memory::IsValidAddress(cbFunc)) { + // There args are supposed to be constructed in the stack and the data need to be available even after returning from this function, so these args + optional data probably copied to somewhere + NpMatching2Args args = {}; + args.data[0] = PSP_NP_MATCHING2_EVENT_0107; + args.data[1] = PSP_NP_MATCHING2_STATE_3208; + //args.data[2] = pointer to arg[8] + args.data[3] = optParamPtr; + args.data[4] = 0; + args.data[5] = assignedReqIdPtr; + args.data[6] = 0; + //args.data[8] = reqParamPtr; + + notifyNpMatching2Handlers(args, ctxId, 0, cbFunc, cbArg, 0, 0, 0, 0x10); + + Memory::Write_U32(args.data[1], assignedReqIdPtr); // server status or flags? + } + + // After returning, Fat Princess will loop for 64 times (increasing the address by 288 bytes on each loop) or until found a zero status byte (0x08BD4860 + 0x10), looking for empty/available entry to set? + return 0; +} + +const HLEFunction sceNpMatching2[] = { + {0x2E61F6E1, &WrapI_IIII, "sceNpMatching2Init", 'i', "iiii" }, + {0x8BF37D8C, &WrapI_V, "sceNpMatching2Term", 'i', "" }, + {0x5030CC53, &WrapI_UUUI, "sceNpMatching2CreateContext", 'i', "xxxi" }, + {0x190FF903, &WrapI_I, "sceNpMatching2ContextStart", 'i', "i" }, + {0x2B3892FC, &WrapI_I, "sceNpMatching2ContextStop", 'i', "i" }, + {0x3DE70241, &WrapI_I, "sceNpMatching2DestroyContext", 'i', "i" }, + {0x22F38DAF, &WrapI_U, "sceNpMatching2GetMemoryStat", 'i', "x" }, + {0xA3C298D1, &WrapI_IUU, "sceNpMatching2RegisterSignalingCallback", 'i', "ixx" }, + {0xF47342FC, &WrapI_IUI, "sceNpMatching2GetServerIdListLocal", 'i', "ixi" }, + {0x4EE3A8EC, &WrapI_IUUU, "sceNpMatching2GetServerInfo", 'i', "ixxx" }, + {0xC870535A, &WrapI_IUUU, "sceNpMatching2LeaveRoom", 'i', "ixxx" }, + {0xAAD0946A, &WrapI_IUUUUU, "sceNpMatching2JoinRoom", 'i', "ixxxxx" }, + {0x81C13E6D, &WrapI_IUUU, "sceNpMatching2SearchRoom", 'i', "ixxx" }, + {0x55F7837F, &WrapI_IUUU, "sceNpMatching2SendRoomChatMessage", 'i', "ixxx" }, +}; + +void Register_sceNpMatching2() +{ + RegisterModule("sceNpMatching2", ARRAY_SIZE(sceNpMatching2), sceNpMatching2); +} diff --git a/Core/HLE/sceNp2.h b/Core/HLE/sceNp2.h new file mode 100644 index 0000000000..712688f22d --- /dev/null +++ b/Core/HLE/sceNp2.h @@ -0,0 +1,254 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + + +#pragma pack(push,1) + +// Based on https://gist.githubusercontent.com/raw/4140449/PS%20Vita (Might be slightly different with PSP?) +#define SCE_NP_MATCHING2_ERROR_OUT_OF_MEMORY 0x80550c01 +#define SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED 0x80550c02 +#define SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED 0x80550c03 +#define SCE_NP_MATCHING2_ERROR_CONTEXT_MAX 0x80550c04 // might be "Invalid Argument" on PSP? +#define SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_EXISTS 0x80550c05 // might be "Context Max/Context Id higher than 7" on PSP? +#define SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND 0x80550c06 +#define SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED 0x80550c07 +#define SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED 0x80550c08 +#define SCE_NP_MATCHING2_ERROR_SERVER_NOT_FOUND 0x80550c09 +#define SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT 0x80550c0a +#define SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID 0x80550c0b +#define SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID 0x80550c0c +#define SCE_NP_MATCHING2_ERROR_INVALID_LOBBY_ID 0x80550c0e +#define SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID 0x80550c0f +#define SCE_NP_MATCHING2_ERROR_INVALID_MEMBER_ID 0x80550c10 +#define SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_ID 0x80550c11 +#define SCE_NP_MATCHING2_ERROR_INVALID_CASTTYPE 0x80550c12 +#define SCE_NP_MATCHING2_ERROR_INVALID_SORT_METHOD 0x80550c13 +#define SCE_NP_MATCHING2_ERROR_INVALID_MAX_SLOT 0x80550c14 +#define SCE_NP_MATCHING2_ERROR_INVALID_OPT_SIZE 0x80550c15 +#define SCE_NP_MATCHING2_ERROR_INVALID_MATCHING_SPACE 0x80550c16 +#define SCE_NP_MATCHING2_ERROR_INVALID_BLOCK_KICK_FLAG 0x80550c18 +#define SCE_NP_MATCHING2_ERROR_INVALID_MESSAGE_TARGET 0x80550c19 +#define SCE_NP_MATCHING2_ERROR_RANGE_FILTER_MAX 0x80550c1a +#define SCE_NP_MATCHING2_ERROR_INVALID_ALIGNMENT 0x80550c1e +#define SCE_NP_MATCHING2_ERROR_CONNECTION_CLOSED_BY_SERVER 0x80550c22 +#define SCE_NP_MATCHING2_ERROR_SSL_VERIFY_FAILED 0x80550c23 +#define SCE_NP_MATCHING2_ERROR_SSL_HANDSHAKE 0x80550c24 +#define SCE_NP_MATCHING2_ERROR_SSL_SEND 0x80550c25 +#define SCE_NP_MATCHING2_ERROR_SSL_RECV 0x80550c26 +#define SCE_NP_MATCHING2_ERROR_JOINED_SESSION_MAX 0x80550c27 +#define SCE_NP_MATCHING2_ERROR_ALREADY_JOINED 0x80550c28 +#define SCE_NP_MATCHING2_ERROR_INVALID_SESSION_TYPE 0x80550c29 +#define SCE_NP_MATCHING2_ERROR_NP_SIGNED_OUT 0x80550c2b +#define SCE_NP_MATCHING2_ERROR_BUSY 0x80550c2c +#define SCE_NP_MATCHING2_ERROR_SERVER_NOT_AVAILABLE 0x80550c2d +#define SCE_NP_MATCHING2_ERROR_NOT_ALLOWED 0x80550c2e +#define SCE_NP_MATCHING2_ERROR_ABORTED 0x80550c2f +#define SCE_NP_MATCHING2_ERROR_REQUEST_NOT_FOUND 0x80550c30 +#define SCE_NP_MATCHING2_ERROR_SESSION_DESTROYED 0x80550c31 +#define SCE_NP_MATCHING2_ERROR_CONTEXT_STOPPED 0x80550c32 +#define SCE_NP_MATCHING2_ERROR_INVALID_REQUEST_PARAMETER 0x80550c33 +#define SCE_NP_MATCHING2_ERROR_NOT_NP_SIGN_IN 0x80550c34 +#define SCE_NP_MATCHING2_ERROR_ROOM_NOT_FOUND 0x80550c35 +#define SCE_NP_MATCHING2_ERROR_ROOM_MEMBER_NOT_FOUND 0x80550c36 +#define SCE_NP_MATCHING2_ERROR_LOBBY_NOT_FOUND 0x80550c37 +#define SCE_NP_MATCHING2_ERROR_LOBBY_MEMBER_NOT_FOUND 0x80550c38 +#define SCE_NP_MATCHING2_ERROR_KEEPALIVE_TIMEOUT 0x80550c3a +#define SCE_NP_MATCHING2_ERROR_TIMEOUT_TOO_SHORT 0x80550c3b +#define SCE_NP_MATCHING2_ERROR_TIMEDOUT 0x80550c3c +#define SCE_NP_MATCHING2_ERROR_INVALID_SLOTGROUP 0x80550c3d +#define SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_SIZE 0x80550c3e +#define SCE_NP_MATCHING2_ERROR_CANNOT_ABORT 0x80550c3f +#define SCE_NP_MATCHING2_ERROR_SESSION_NOT_FOUND 0x80550c40 + +#define SCE_NP_MATCHING2_SERVER_ERROR_BAD_REQUEST 0x80550d01 +#define SCE_NP_MATCHING2_SERVER_ERROR_SERVICE_UNAVAILABLE 0x80550d02 +#define SCE_NP_MATCHING2_SERVER_ERROR_BUSY 0x80550d03 +#define SCE_NP_MATCHING2_SERVER_ERROR_END_OF_SERVICE 0x80550d04 +#define SCE_NP_MATCHING2_SERVER_ERROR_INTERNAL_SERVER_ERROR 0x80550d05 +#define SCE_NP_MATCHING2_SERVER_ERROR_PLAYER_BANNED 0x80550d06 +#define SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN 0x80550d07 +#define SCE_NP_MATCHING2_SERVER_ERROR_BLOCKED 0x80550d08 +#define SCE_NP_MATCHING2_SERVER_ERROR_UNSUPPORTED_NP_ENV 0x80550d09 +#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_TICKET 0x80550d0a +#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_SIGNATURE 0x80550d0b +#define SCE_NP_MATCHING2_SERVER_ERROR_EXPIRED_TICKET 0x80550d0c +#define SCE_NP_MATCHING2_SERVER_ERROR_ENTITLEMENT_REQUIRED 0x80550d0d +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_CONTEXT 0x80550d0e +#define SCE_NP_MATCHING2_SERVER_ERROR_CLOSED 0x80550d0f +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_TITLE 0x80550d10 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_WORLD 0x80550d11 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_LOBBY 0x80550d12 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM 0x80550d13 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_LOBBY_INSTANCE 0x80550d14 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM_INSTANCE 0x80550d15 +#define SCE_NP_MATCHING2_SERVER_ERROR_PASSWORD_MISMATCH 0x80550d17 +#define SCE_NP_MATCHING2_SERVER_ERROR_LOBBY_FULL 0x80550d18 +#define SCE_NP_MATCHING2_SERVER_ERROR_ROOM_FULL 0x80550d19 +#define SCE_NP_MATCHING2_SERVER_ERROR_GROUP_FULL 0x80550d1b +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER 0x80550d1c +#define SCE_NP_MATCHING2_SERVER_ERROR_TITLE_PASSPHRASE_MISMATCH 0x80550d1e +#define SCE_NP_MATCHING2_SERVER_ERROR_CONSOLE_BANNED 0x80550d28 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_ROOMGROUP 0x80550d29 +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_GROUP 0x80550d2a +#define SCE_NP_MATCHING2_SERVER_ERROR_NO_PASSWORD 0x80550d2b +#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_GROUP_SLOT_NUM 0x80550d2c +#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_PASSWORD_SLOT_MASK 0x80550d2d +#define SCE_NP_MATCHING2_SERVER_ERROR_DUPLICATE_GROUP_LABEL 0x80550d2e +#define SCE_NP_MATCHING2_SERVER_ERROR_REQUEST_OVERFLOW 0x80550d2f +#define SCE_NP_MATCHING2_SERVER_ERROR_ALREADY_JOINED 0x80550d30 +#define SCE_NP_MATCHING2_SERVER_ERROR_NAT_TYPE_MISMATCH 0x80550d31 +#define SCE_NP_MATCHING2_SERVER_ERROR_ROOM_INCONSISTENCY 0x80550d32 + +#define SCE_NP_MATCHING2_SIGNALING_ERROR_NOT_INITIALIZED 0x80550e01 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_ALREADY_INITIALIZED 0x80550e02 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_OUT_OF_MEMORY 0x80550e03 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTXID_NOT_AVAILABLE 0x80550e04 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTX_NOT_FOUND 0x80550e05 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_REQID_NOT_AVAILABLE 0x80550e06 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_REQ_NOT_FOUND 0x80550e07 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_PARSER_CREATE_FAILED 0x80550e08 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_PARSER_FAILED 0x80550e09 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_INVALID_NAMESPACE 0x80550e0a +#define SCE_NP_MATCHING2_SIGNALING_ERROR_NETINFO_NOT_AVAILABLE 0x80550e0b +#define SCE_NP_MATCHING2_SIGNALING_ERROR_PEER_NOT_RESPONDING 0x80550e0c +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONNID_NOT_AVAILABLE 0x80550e0d +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONN_NOT_FOUND 0x80550e0e +#define SCE_NP_MATCHING2_SIGNALING_ERROR_PEER_UNREACHABLE 0x80550e0f +#define SCE_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_PEER 0x80550e10 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_TIMEOUT 0x80550e11 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTX_MAX 0x80550e12 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_RESULT_NOT_FOUND 0x80550e13 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONN_IN_PROGRESS 0x80550e14 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_INVALID_ARGUMENT 0x80550e15 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_OWN_NP_ID 0x80550e16 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_TOO_MANY_CONN 0x80550e17 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_MYSELF 0x80550e18 +#define SCE_NP_MATCHING2_SIGNALING_ERROR_MATCHING2_PEER_NOT_FOUND 0x80550e19 + +// Based on https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.h (Just as reference, might be slightly different than PSP) +// Event of request functions +enum PS3Matching2RequestEvent +{ + SCE_NP_MATCHING2_REQUEST_EVENT_GetServerInfo = 0x0001, + SCE_NP_MATCHING2_REQUEST_EVENT_GetWorldInfoList = 0x0002, + SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataExternalList = 0x0003, + SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal = 0x0004, + SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList = 0x0005, + SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyInfoList = 0x0006, + SCE_NP_MATCHING2_REQUEST_EVENT_SetUserInfo = 0x0007, + SCE_NP_MATCHING2_REQUEST_EVENT_GetUserInfoList = 0x0008, + SCE_NP_MATCHING2_REQUEST_EVENT_CreateServerContext = 0x0009, + SCE_NP_MATCHING2_REQUEST_EVENT_DeleteServerContext = 0x000a, + SCE_NP_MATCHING2_REQUEST_EVENT_CreateJoinRoom = 0x0101, + SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom = 0x0102, + SCE_NP_MATCHING2_REQUEST_EVENT_LeaveRoom = 0x0103, + SCE_NP_MATCHING2_REQUEST_EVENT_GrantRoomOwner = 0x0104, + SCE_NP_MATCHING2_REQUEST_EVENT_KickoutRoomMember = 0x0105, + SCE_NP_MATCHING2_REQUEST_EVENT_SearchRoom = 0x0106, + SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomChatMessage = 0x0107, + SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomMessage = 0x0108, + SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataInternal = 0x0109, + SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataInternal = 0x010a, + SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomMemberDataInternal = 0x010b, + SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataInternal = 0x010c, + SCE_NP_MATCHING2_REQUEST_EVENT_SetSignalingOptParam = 0x010d, + SCE_NP_MATCHING2_REQUEST_EVENT_JoinLobby = 0x0201, + SCE_NP_MATCHING2_REQUEST_EVENT_LeaveLobby = 0x0202, + SCE_NP_MATCHING2_REQUEST_EVENT_SendLobbyChatMessage = 0x0203, + SCE_NP_MATCHING2_REQUEST_EVENT_SendLobbyInvitation = 0x0204, + SCE_NP_MATCHING2_REQUEST_EVENT_SetLobbyMemberDataInternal = 0x0205, + SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyMemberDataInternal = 0x0206, + SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyMemberDataInternalList = 0x0207, + SCE_NP_MATCHING2_REQUEST_EVENT_SignalingGetPingInfo = 0x0e01, +}; + +// Based on decompiled np_matching2.prx, commented with syscalls where the event id is being used +#define PSP_NP_MATCHING2_EVENT_0001 0x0001 // GetServerInfo +#define PSP_NP_MATCHING2_EVENT_0002 0x0002 // GetWorldInfoList +#define PSP_NP_MATCHING2_EVENT_0003 0x0003 // SetUserInfo +#define PSP_NP_MATCHING2_EVENT_0004 0x0004 // GetUserInfoList +#define PSP_NP_MATCHING2_EVENT_0005 0x0005 // GetRoomMemberDataExternalList +#define PSP_NP_MATCHING2_EVENT_0006 0x0006 // SetRoomDataExternal +#define PSP_NP_MATCHING2_EVENT_0007 0x0007 // GetRoomDataExternalList + +#define PSP_NP_MATCHING2_EVENT_0101 0x0101 // CreateJoinRoom +#define PSP_NP_MATCHING2_EVENT_0102 0x0102 // JoinRoom +#define PSP_NP_MATCHING2_EVENT_0103 0x0103 // LeaveRoom +#define PSP_NP_MATCHING2_EVENT_0104 0x0104 // GrantRoomOwner +#define PSP_NP_MATCHING2_EVENT_0105 0x0105 // KickoutRoomMember +#define PSP_NP_MATCHING2_EVENT_0106 0x0106 // SearchRoom +#define PSP_NP_MATCHING2_EVENT_0107 0x0107 // SendRoomChatMessage +#define PSP_NP_MATCHING2_EVENT_0108 0x0108 // SendRoomMessage, also used on various places (internal function) +#define PSP_NP_MATCHING2_EVENT_0109 0x0109 // SetRoomDataInternal +#define PSP_NP_MATCHING2_EVENT_010A 0x010A // GetRoomDataInternal +#define PSP_NP_MATCHING2_EVENT_010B 0x010B // SetRoomMemberDataInternal +#define PSP_NP_MATCHING2_EVENT_010C 0x010C // GetRoomMemberDataInternal +#define PSP_NP_MATCHING2_EVENT_010D 0x010D // GetRoomMemberDataInternalList +#define PSP_NP_MATCHING2_EVENT_010E 0x010E // SetSignalingOptParam + +#define PSP_NP_MATCHING2_EVENT_A102 0xA102 // Used on various places (internal function) + +// Either this is an ID, state/status, flags, or might be size of data? +#define PSP_NP_MATCHING2_STATE_1001 0x1001 +#define PSP_NP_MATCHING2_STATE_1006 0x1006 +#define PSP_NP_MATCHING2_STATE_1007 0x1007 +#define PSP_NP_MATCHING2_STATE_1008 0x1008 + +#define PSP_NP_MATCHING2_STATE_1200 0x1200 +#define PSP_NP_MATCHING2_STATE_1206 0x1206 +#define PSP_NP_MATCHING2_STATE_1207 0x1207 +#define PSP_NP_MATCHING2_STATE_1208 0x1208 +#define PSP_NP_MATCHING2_STATE_1209 0x1209 +#define PSP_NP_MATCHING2_STATE_120B 0x120B +#define PSP_NP_MATCHING2_STATE_120C 0x120C + +#define PSP_NP_MATCHING2_STATE_3202 0x3202 +#define PSP_NP_MATCHING2_STATE_3203 0x3203 +#define PSP_NP_MATCHING2_STATE_3204 0x3204 +#define PSP_NP_MATCHING2_STATE_3205 0x3205 +#define PSP_NP_MATCHING2_STATE_3206 0x3206 +#define PSP_NP_MATCHING2_STATE_3207 0x3207 +#define PSP_NP_MATCHING2_STATE_3208 0x3208 +#define PSP_NP_MATCHING2_STATE_320A 0x320A +#define PSP_NP_MATCHING2_STATE_3210 0x3210 +#define PSP_NP_MATCHING2_STATE_3211 0x3211 + +#define PSP_NP_MATCHING2_MAX_CONTEXTID 7; + +struct NpMatching2Handler { + u32 entryPoint; + u32 argument; +}; + +// Arg1 and Arg2 seems to be a pair and predefined: 0x0001 with 0x1001, 0x0002 with 0x1008, 0x0003 with 0x1006, 0x0004 with 0x1007, +// 0x0005 with 0x1206, 0x0006 with 0x1207, 0x0007 with 0x1208, 0x0101 with 0x1209, 0x0102 with 0x1209, 0x0103 with 0x3202, +// 0x0104 with 0x3210, 0x0105 with 0x3211, 0x0106 with 2 possibilities (0x1200 and 0x120c), 0x0107 with 0x3208, 0x0108 with 0x320a, +// 0x0109 with 0x3204, 0x010a with 0x3205, 0x010b with 0x3206, 0x010c with 0x3207, 0x010d with 0x3203, 0x010e with 0x3204, +// 0xa102 with 0x120b. +// Arg5 seems to be boolean (0/1), mostly 0, conditional when Arg1=0x0001 +// Arg7 seems to be integer/state? (0..2), mostly 0, conditional when Arg1=0x0108 (0 on SendRoomMessage, 2 on others), 1 when Arg1=0xa102 +struct NpMatching2Args { + u32_le data[11]; // 7 elements (excluding optional data)? or may be 11 elements (including optional data)? + // May be followed by optional data? since these Args usually created on the stack +}; + +#pragma pack(pop) + + +void Register_sceNpMatching2(); diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 16863bd6e9..0777e28251 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -441,6 +441,7 @@ + @@ -677,6 +678,7 @@ + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index 6ceb09e6b5..b1f23b19fb 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -1115,6 +1115,9 @@ + + HLE + @@ -1761,6 +1764,9 @@ + + HLE + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 33db892245..a0c9774d37 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -518,6 +518,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/HLE/scePspNpDrm_user.cpp \ $(SRC)/Core/HLE/sceGameUpdate.cpp \ $(SRC)/Core/HLE/sceNp.cpp \ + $(SRC)/Core/HLE/sceNp2.cpp \ $(SRC)/Core/HLE/scePauth.cpp \ $(SRC)/Core/FileSystems/BlobFileSystem.cpp \ $(SRC)/Core/FileSystems/BlockDevices.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index dca3bde0d1..9143600e09 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -547,6 +547,7 @@ SOURCES_CXX += \ $(COREDIR)/HLE/sceVaudio.cpp \ $(COREDIR)/HLE/scePspNpDrm_user.cpp \ $(COREDIR)/HLE/sceNp.cpp \ + $(COREDIR)/HLE/sceNp2.cpp \ $(COREDIR)/HLE/scePauth.cpp \ $(COREDIR)/HLE/sceUsbGps.cpp \ $(COREDIR)/HW/BufferQueue.cpp \ From 865959d420651684c65f5efec8c0bd0a876a6f90 Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Mon, 30 May 2022 02:42:00 +0700 Subject: [PATCH 33/35] Replace the dummy PSN name with Nickname on sceNpInit. --- Core/HLE/sceNp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/HLE/sceNp.cpp b/Core/HLE/sceNp.cpp index c7328a8ed0..9a62ff5167 100644 --- a/Core/HLE/sceNp.cpp +++ b/Core/HLE/sceNp.cpp @@ -21,6 +21,7 @@ #include #include "Core/MemMapHelpers.h" #include +#include #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceNp.h" @@ -105,6 +106,8 @@ void notifyNpAuthHandlers(u32 id, u32 result, u32 argAddr) { static int sceNpInit() { ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); + npOnlineId = g_Config.sNickName; + return 0; } From 31ea7a6a9517635c79876b208f45badbd9c14419 Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Thu, 4 Aug 2022 16:34:05 +0700 Subject: [PATCH 34/35] Updated copyright's year. --- Core/HLE/sceNp2.cpp | 2 +- Core/HLE/sceNp2.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceNp2.cpp b/Core/HLE/sceNp2.cpp index 588471ba37..ad01e4ec2b 100644 --- a/Core/HLE/sceNp2.cpp +++ b/Core/HLE/sceNp2.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012- PPSSPP Project. +// Copyright (c) 2022- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/Core/HLE/sceNp2.h b/Core/HLE/sceNp2.h index 712688f22d..8b1b6c1c56 100644 --- a/Core/HLE/sceNp2.h +++ b/Core/HLE/sceNp2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012- PPSSPP Project. +// Copyright (c) 2022- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by From 4c9e1dec1a137c3b4b2b94834be38139747f9f80 Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Thu, 4 Aug 2022 16:35:30 +0700 Subject: [PATCH 35/35] Fix include issue. --- Core/Dialog/PSPNpSigninDialog.cpp | 2 +- Core/HLE/sceNp.cpp | 6 ++++-- Core/HLE/sceNp.h | 2 +- Core/HLE/sceNp2.cpp | 4 +++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Core/Dialog/PSPNpSigninDialog.cpp b/Core/Dialog/PSPNpSigninDialog.cpp index f6621db66c..87fcf602c5 100644 --- a/Core/Dialog/PSPNpSigninDialog.cpp +++ b/Core/Dialog/PSPNpSigninDialog.cpp @@ -18,7 +18,7 @@ #if defined(_WIN32) #include "Common/CommonWindows.h" #endif -#include +#include "Common/TimeUtil.h" #include "Common/Data/Text/I18n.h" #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" diff --git a/Core/HLE/sceNp.cpp b/Core/HLE/sceNp.cpp index 9a62ff5167..4c71f3db55 100644 --- a/Core/HLE/sceNp.cpp +++ b/Core/HLE/sceNp.cpp @@ -18,10 +18,12 @@ // This is pretty much a stub implementation. Doesn't actually do anything, just tries to return values // to keep games happy anyway. +#include +#include #include #include "Core/MemMapHelpers.h" -#include -#include +#include "Core/CoreTiming.h" +#include "Core/Config.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceNp.h" diff --git a/Core/HLE/sceNp.h b/Core/HLE/sceNp.h index ed2a30646d..b937213546 100644 --- a/Core/HLE/sceNp.h +++ b/Core/HLE/sceNp.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include "Core/HLE/sceRtc.h" #include "Common/Net/HTTPClient.h" #include "Common/Net/Resolve.h" #include "Common/Net/URL.h" diff --git a/Core/HLE/sceNp2.cpp b/Core/HLE/sceNp2.cpp index ad01e4ec2b..b0a7565fde 100644 --- a/Core/HLE/sceNp2.cpp +++ b/Core/HLE/sceNp2.cpp @@ -18,9 +18,11 @@ // This is pretty much a stub implementation. Doesn't actually do anything, just tries to return values // to keep games happy anyway. +#include +#include #include #include "Core/MemMapHelpers.h" -#include +#include "Core/CoreTiming.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceNp.h"