Merge branch 'master' into feature_openxr_6dof

This commit is contained in:
Lubos committed 2022-08-05 13:49:42 +02:00
commit 5f377f82eb
63 files changed
+2724 -2047

No files matched your search

+6 -4
View File
@@ -1459,7 +1459,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
@@ -1483,7 +1482,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
@@ -1503,7 +1501,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
)
@@ -1523,7 +1520,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
)
@@ -1537,6 +1533,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
@@ -1715,6 +1713,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
@@ -1898,6 +1898,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
+17 -4
View File
@@ -38,6 +38,7 @@ class D3D11Pipeline;
class D3D11BlendState;
class D3D11DepthStencilState;
class D3D11SamplerState;
class D3D11Buffer;
class D3D11RasterState;
class D3D11Framebuffer;
@@ -248,10 +249,12 @@ private:
uint8_t stencilRef_ = 0;
uint8_t stencilWriteMask_ = 0xFF;
uint8_t stencilCompareMask_ = 0xFF;
bool stencilDirty_ = true;
// Temporaries
ID3D11Texture2D *packTexture_ = nullptr;
Buffer *upBuffer_ = nullptr;
// System info
D3D_FEATURE_LEVEL featureLevel_;
@@ -282,7 +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; // Though could be emulated with a draw.
caps_.texture3DSupported = true;
D3D11_FEATURE_DATA_D3D11_OPTIONS options{};
@@ -337,9 +342,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.
@@ -755,9 +765,6 @@ public:
shaderModule->Release();
}
}
bool RequiresBuffer() override {
return true;
}
AutoRef<D3D11InputLayout> input;
ID3D11InputLayout *il = nullptr;
@@ -1247,7 +1254,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 {
+24 -8
View File
@@ -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"
@@ -272,9 +273,6 @@ public:
D3D9Pipeline() {}
~D3D9Pipeline() {
}
bool RequiresBuffer() override {
return false;
}
D3D9ShaderModule *vshader;
D3D9ShaderModule *pshader;
@@ -666,7 +664,9 @@ 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;
if (d3d) {
@@ -1064,6 +1064,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)
@@ -1241,14 +1245,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) {
+5 -9
View File
@@ -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<OpenGLShaderModule *> shaders;
AutoRef<OpenGLInputLayout> inputLayout;
@@ -541,8 +534,11 @@ 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_.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;
@@ -1117,7 +1113,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;
}
+2
View File
@@ -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";
}
+2
View File
@@ -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;
+56 -16
View File
@@ -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<InputDef> inputs, Slice<UniformDef> 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");
@@ -162,24 +172,37 @@ void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> 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, 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:
{
for (auto &input : inputs) {
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;
}
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);
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;
@@ -191,14 +214,19 @@ void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> 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) {
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);
@@ -212,7 +240,7 @@ void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> 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);
@@ -221,14 +249,25 @@ void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> 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()) {
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);
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);
}
if (!strcmp(lang_.fragColor0, "fragColor0")) {
C("out vec4 fragColor0;\n");
@@ -284,6 +323,7 @@ void ShaderWriter::DeclareTexture2D(const char *name, int binding) {
F("Texture2D<float4> %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.
+2 -1
View File
@@ -19,6 +19,7 @@
struct InputDef {
const char *type;
const char *name;
int semantic;
};
struct UniformDef {
@@ -30,7 +31,7 @@ struct UniformDef {
struct VaryingDef {
const char *type;
const char *name;
const char *semantic;
int semantic;
int index;
const char *precision;
};
+16 -9
View File
@@ -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;
@@ -578,7 +575,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 +771,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 +783,10 @@ 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_.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.
caps_.texture3DSupported = true;
@@ -1440,18 +1441,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;
}
+8 -5
View File
@@ -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,
};
@@ -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 {
@@ -448,7 +450,6 @@ public:
class Pipeline : public RefCountedObject {
public:
virtual ~Pipeline() {}
virtual bool RequiresBuffer() = 0;
};
class RasterState : public RefCountedObject {};
@@ -530,7 +531,9 @@ struct DeviceCaps {
bool framebufferCopySupported;
bool framebufferBlitSupported;
bool framebufferDepthCopySupported;
bool framebufferSeparateDepthCopySupported;
bool framebufferDepthBlitSupported;
bool framebufferStencilBlitSupported;
bool framebufferFetchSupported;
bool texture3DSupported;
+1 -18
View File
@@ -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;
}
-1
View File
@@ -199,7 +199,6 @@ private:
std::vector<float> alphaStack_;
Draw::DrawContext *draw_ = nullptr;
Draw::Buffer *vbuf_ = nullptr;
Draw::Pipeline *pipeline_ = nullptr;
Vertex *verts_;
+1 -1
View File
@@ -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;
}
+4
View File
@@ -535,6 +535,7 @@
<ClCompile Include="HLE\KUBridge.cpp" />
<ClCompile Include="HLE\Plugins.cpp" />
<ClCompile Include="HLE\sceKernelHeap.cpp" />
<ClCompile Include="HLE\sceNp2.cpp" />
<ClCompile Include="HLE\sceUsbAcc.cpp" />
<ClCompile Include="HLE\sceUsbCam.cpp" />
<ClCompile Include="HLE\sceUsbMic.cpp" />
@@ -572,6 +573,7 @@
<ClCompile Include="Dialog\PSPDialog.cpp" />
<ClCompile Include="Dialog\PSPMsgDialog.cpp" />
<ClCompile Include="Dialog\PSPNetconfDialog.cpp" />
<ClCompile Include="Dialog\PSPNpSigninDialog.cpp" />
<ClCompile Include="Dialog\PSPOskDialog.cpp" />
<ClCompile Include="Dialog\PSPPlaceholderDialog.cpp" />
<ClCompile Include="Dialog\PSPSaveDialog.cpp" />
@@ -1086,6 +1088,7 @@
<ClInclude Include="HLE\KUBridge.h" />
<ClInclude Include="HLE\Plugins.h" />
<ClInclude Include="HLE\sceKernelHeap.h" />
<ClInclude Include="HLE\sceNp2.h" />
<ClInclude Include="HLE\sceUsbAcc.h" />
<ClInclude Include="HLE\sceUsbCam.h" />
<ClInclude Include="HLE\sceUsbMic.h" />
@@ -1118,6 +1121,7 @@
<ClInclude Include="Dialog\PSPDialog.h" />
<ClInclude Include="Dialog\PSPMsgDialog.h" />
<ClInclude Include="Dialog\PSPNetconfDialog.h" />
<ClInclude Include="Dialog\PSPNpSigninDialog.h" />
<ClInclude Include="Dialog\PSPOskDialog.h" />
<ClInclude Include="Dialog\PSPPlaceholderDialog.h" />
<ClInclude Include="Dialog\PSPSaveDialog.h" />
+12
View File
@@ -523,6 +523,9 @@
<ClCompile Include="Dialog\PSPNetconfDialog.cpp">
<Filter>Dialog</Filter>
</ClCompile>
<ClCompile Include="Dialog\PSPNpSigninDialog.cpp">
<Filter>Dialog</Filter>
</ClCompile>
<ClCompile Include="Debugger\DisassemblyManager.cpp">
<Filter>Debugger</Filter>
</ClCompile>
@@ -1184,6 +1187,9 @@
<ClCompile Include="HW\Display.cpp">
<Filter>HW</Filter>
</ClCompile>
<ClCompile Include="HLE\sceNp2.cpp">
<Filter>HLE\Libraries</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@@ -1597,6 +1603,9 @@
<ClInclude Include="Dialog\PSPNetconfDialog.h">
<Filter>Dialog</Filter>
</ClInclude>
<ClInclude Include="Dialog\PSPNpSigninDialog.h">
<Filter>Dialog</Filter>
</ClInclude>
<ClInclude Include="MIPS\JitCommon\JitState.h">
<Filter>MIPS\JitCommon</Filter>
</ClInclude>
@@ -1910,6 +1919,9 @@
<ClInclude Include="HW\Display.h">
<Filter>HW</Filter>
</ClInclude>
<ClInclude Include="HLE\sceNp2.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
+349
View File
@@ -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 "Common/TimeUtil.h"
#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;
}
+67
View File
@@ -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;
};
+5
View File
@@ -765,6 +765,11 @@ template<u32 func(u32, u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUUU() {
RETURN(retval);
}
template<int func(int, u32, u32, u32, u32, u32, u32)> void WrapI_IUUUUUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval);
}
template<int func(u32, int, u32, u32)> void WrapI_UIUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
+279 -77
View File
@@ -20,26 +20,32 @@
#include <mutex>
#include <deque>
#include <map>
#include <StringUtils.h>
#include "Core/MemMapHelpers.h"
#include <Core/CoreTiming.h>
#include "Core/CoreTiming.h"
#include "Core/Config.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/sceNp.h"
#include <Core/HLE/sceRtc.h>
bool npAuthInited = false;
int npSigninState = NP_SIGNIN_STATUS_NONE;
SceNpAuthMemoryStat npAuthMemStat = {};
std::string serviceId = "";
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?
SceNpCommunicationId npTitleId;
std::recursive_mutex npAuthEvtMtx;
std::deque<NpAuthArgs> npAuthEvents;
@@ -53,7 +59,8 @@ int writeTicketParam(u8* buffer, const u16_be type, const char* data = nullptr,
u16_be sz = (data == nullptr)? static_cast<u16_be>(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;
}
@@ -100,38 +107,149 @@ void notifyNpAuthHandlers(u32 id, u32 result, u32 argAddr) {
static int sceNpInit()
{
ERROR_LOG(HLE, "UNIMPL %s()", __FUNCTION__);
ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__);
npOnlineId = g_Config.sNickName;
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 +259,11 @@ const HLEFunction sceNp[] = {
{0X37E1E274, &WrapI_V<sceNpTerm>, "sceNpTerm", 'i', "" },
{0XBB069A87, &WrapI_UU<sceNpGetContentRatingFlag>, "sceNpGetContentRatingFlag", 'i', "xx" },
{0X1D60AE4B, &WrapI_U<sceNpGetChatRestrictionFlag>, "sceNpGetChatRestrictionFlag", 'i', "x" },
{0x4B5C71C8, &WrapI_U<sceNpGetOnlineId>, "sceNpGetOnlineId", 'i', "x" },
{0x633B5F71, &WrapI_U<sceNpGetNpId>, "sceNpGetNpId", 'i', "x" },
{0x7E0864DF, &WrapI_U<sceNpGetUserProfile>, "sceNpGetUserProfile", 'i', "x" },
{0xA0BE3C4B, &WrapI_UU<sceNpGetAccountRegion>, "sceNpGetAccountRegion", 'i', "xx" },
{0xCDCC21D3, &WrapI_U<sceNpGetMyLanguages>, "sceNpGetMyLanguages", 'i', "x" },
};
void Register_sceNp()
@@ -151,29 +274,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 +315,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(&params, 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 +378,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 +393,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 +431,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<std::recursive_mutex> 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 +464,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<unsigned int>(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>, "sceNpAuthTerm", 'i', "" },
{0XA1DE86F8, &WrapI_UUU<sceNpAuthInit>, "sceNpAuthInit", 'i', "xxx" },
{0XF4531ADC, &WrapI_U<sceNpAuthGetMemoryStat>, "sceNpAuthGetMemoryStat", 'i', "x" },
{0XCD86A656, &WrapI_U<sceNpAuthCreateStartRequest>, "sceNpAuthCreateStartRequest", 'i', "x" },
{0X3F1C1F70, &WrapI_UUU<sceNpAuthGetTicket>, "sceNpAuthGetTicket", 'i', "xxx" },
{0X6900F084, &WrapI_UUUU<sceNpAuthGetEntitlementById>, "sceNpAuthGetEntitlementById", 'i', "xxxx" },
{0XD99455DD, &WrapI_I<sceNpAuthAbortRequest>, "sceNpAuthAbortRequest", 'i', "i" },
{0X72BB0467, &WrapI_I<sceNpAuthDestroyRequest>, "sceNpAuthDestroyRequest", 'i', "i" },
{0X4EC1F667, &WrapI_V<sceNpAuthTerm>, "sceNpAuthTerm", 'i', "" },
{0XA1DE86F8, &WrapI_UUU<sceNpAuthInit>, "sceNpAuthInit", 'i', "xxx" },
{0XF4531ADC, &WrapI_U<sceNpAuthGetMemoryStat>, "sceNpAuthGetMemoryStat", 'i', "x" },
{0XCD86A656, &WrapI_U<sceNpAuthCreateStartRequest>, "sceNpAuthCreateStartRequest", 'i', "x" },
{0X3F1C1F70, &WrapI_UUU<sceNpAuthGetTicket>, "sceNpAuthGetTicket", 'i', "xxx" },
{0X6900F084, &WrapI_UUUU<sceNpAuthGetEntitlementById>, "sceNpAuthGetEntitlementById", 'i', "xxxx" },
{0XD99455DD, &WrapI_I<sceNpAuthAbortRequest>, "sceNpAuthAbortRequest", 'i', "i" },
{0X72BB0467, &WrapI_I<sceNpAuthDestroyRequest>, "sceNpAuthDestroyRequest", 'i', "i" },
{0x5A3CB57A, &WrapI_UIIU<sceNpAuthGetTicketParam>, "sceNpAuthGetTicketParam", 'i', "xiix" },
{0x75FB0AE3, nullptr, "sceNpAuthGetEntitlementIdList", 'i', "" },
};
void Register_sceNpAuth()
@@ -362,46 +518,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>, "sceNpServiceTerm", 'i', "" },
{0X0F8F5821, &WrapI_UUU<sceNpServiceInit>, "sceNpServiceInit", 'i', "xxx" },
{0X5494274B, &WrapI_U<sceNpLookupCreateTransactionCtx>, "sceNpLookupCreateTransactionCtx", 'i', "x" },
{0XA670D3A3, &WrapI_U<sceNpLookupDestroyTransactionCtx>, "sceNpLookupDestroyTransactionCtx", 'i', "x" },
{0XC76F55ED, &WrapI_UUUUU<sceNpLookupTitleSmallStorage>, "sceNpLookupTitleSmallStorage", 'i', "xxxxx" },
{0X00ACFAC3, &WrapI_V<sceNpServiceTerm>, "sceNpServiceTerm", 'i', "" },
{0X0F8F5821, &WrapI_UUU<sceNpServiceInit>, "sceNpServiceInit", 'i', "xxx" },
{0X5494274B, &WrapI_U<sceNpLookupCreateTransactionCtx>, "sceNpLookupCreateTransactionCtx", 'i', "x" },
{0XA670D3A3, &WrapI_I<sceNpLookupDestroyTransactionCtx>, "sceNpLookupDestroyTransactionCtx", 'i', "i" },
{0XC76F55ED, &WrapI_IUUUU<sceNpLookupTitleSmallStorage>, "sceNpLookupTitleSmallStorage", 'i', "ixxxx" },
{0XBE22EEA3, &WrapI_U<sceNpRosterCreateRequest>, "sceNpRosterCreateRequest", 'i', "x" },
{0X4E851B10, &WrapI_IUUUUUU<sceNpRosterGetFriendListEntry>, "sceNpRosterGetFriendListEntry", 'i', "ixxxxxx"},
{0X5F5E32AF, &WrapI_I<sceNpRosterAbort>, "sceNpRosterAbort", 'i', "i" },
{0X66C64821, &WrapI_I<sceNpRosterDeleteRequest>, "sceNpRosterDeleteRequest", 'i', "i" },
};
void Register_sceNpService()
@@ -409,6 +609,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 +633,4 @@ void Register_sceNpCommerce2()
{
RegisterModule("sceNpCommerce2", ARRAY_SIZE(sceNpCommerce2), sceNpCommerce2);
}
+187 -18
View File
@@ -17,9 +17,16 @@
#pragma once
#ifdef _MSC_VER
#include <mutex>
#include <deque>
#include <map>
#include "Core/HLE/sceRtc.h"
#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 +54,140 @@
#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
// Based on https://gist.githubusercontent.com/raw/4140449/PS%20Vita (Might be slightly different with PSP?)
#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 +223,7 @@ struct SceNpCommunicationConfig
PSPPointer<SceNpCommunicationSignature> commSignature;
};
// Part of BCP 47 Code (ie. "fr" for France/French)?
struct SceNpCountryCode
{
char data[2];
@@ -117,6 +259,7 @@ struct SceNpUserInformation
u8 reserved[52];
};
// Language Code (ie. 1033 for "en-US")?
struct SceNpMyLanguages
{
s32_le language1;
@@ -172,8 +315,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<void> arg);
@@ -227,9 +375,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 +390,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 +398,19 @@ 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.
};
#pragma pack(pop)
#define PARENTAL_CONTROL_DISABLED 0
#define PARENTAL_CONTROL_ENABLED 1
@@ -261,22 +418,34 @@ 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<NpAuthArgs> npAuthEvents;
extern std::map<int, NpAuthHandler> 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();
+568
View File
@@ -0,0 +1,568 @@
// 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
// 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 <mutex>
#include <deque>
#include <StringUtils.h>
#include "Core/MemMapHelpers.h"
#include "Core/CoreTiming.h"
#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<NpMatching2Args> npMatching2Events;
std::map<int, NpMatching2Handler> npMatching2Handlers;
//std::map<int, NpMatching2Context> 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<std::recursive_mutex> 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<std::string> 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("<agent-fqdn", ++ofs2);
if (ofs == std::string::npos)
if (i == 1)
return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent-fqdn not found");
else
break;
size_t frontPos = ++ofs;
ofs = entity.find("id=", frontPos);
if (ofs == std::string::npos)
return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent id not found");
ofs += 4;
ofs2 = entity.find('"', ofs);
text = entity.substr(ofs, ofs2 - ofs);
INFO_LOG(SCENET, "%s - Agent-FQDN#%d ID: %s", __FUNCTION__, i, text.c_str());
ofs = entity.find("port=", frontPos);
if (ofs == std::string::npos)
return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent port not found");
ofs += 6;
ofs2 = entity.find('"', ofs);
text = entity.substr(ofs, ofs2 - ofs);
INFO_LOG(SCENET, "%s - Agent-FQDN#%d Port: %s", __FUNCTION__, i, text.c_str());
ofs = entity.find("status=", frontPos);
if (ofs == std::string::npos)
return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "agent status not found");
ofs += 8;
ofs2 = entity.find('"', ofs);
text = entity.substr(ofs, ofs2 - ofs);
INFO_LOG(SCENET, "%s - Agent-FQDN#%d Status: %s", __FUNCTION__, i, text.c_str());
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("</agent-fqdn", ++ofs);
text = entity.substr(ofs, ofs2 - ofs);
INFO_LOG(SCENET, "%s - Agent-FQDN#%d Host: %s", __FUNCTION__, i, text.c_str());
i++;
}
}
hleEatMicro(1000000);
// Returning 0x805508A6 (error code inherited from sceNpService_76867C01 which check server availability) if can't check server availability (ie. Fat Princess (US) through http://static-resource.np.community.playstation.net/np/resource/psp-title/NPWR00670_00/matching/NPWR00670_00-matching.xml using User-Agent: "PS3Community-agent/1.0.0 libhttp/1.0.0")
return 0;
}
static int sceNpMatching2ContextStop(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_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<int, NpMatching2Handler>::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>, "sceNpMatching2Init", 'i', "iiii" },
{0x8BF37D8C, &WrapI_V<sceNpMatching2Term>, "sceNpMatching2Term", 'i', "" },
{0x5030CC53, &WrapI_UUUI<sceNpMatching2CreateContext>, "sceNpMatching2CreateContext", 'i', "xxxi" },
{0x190FF903, &WrapI_I<sceNpMatching2ContextStart>, "sceNpMatching2ContextStart", 'i', "i" },
{0x2B3892FC, &WrapI_I<sceNpMatching2ContextStop>, "sceNpMatching2ContextStop", 'i', "i" },
{0x3DE70241, &WrapI_I<sceNpMatching2DestroyContext>, "sceNpMatching2DestroyContext", 'i', "i" },
{0x22F38DAF, &WrapI_U<sceNpMatching2GetMemoryStat>, "sceNpMatching2GetMemoryStat", 'i', "x" },
{0xA3C298D1, &WrapI_IUU<sceNpMatching2RegisterSignalingCallback>, "sceNpMatching2RegisterSignalingCallback", 'i', "ixx" },
{0xF47342FC, &WrapI_IUI<sceNpMatching2GetServerIdListLocal>, "sceNpMatching2GetServerIdListLocal", 'i', "ixi" },
{0x4EE3A8EC, &WrapI_IUUU<sceNpMatching2GetServerInfo>, "sceNpMatching2GetServerInfo", 'i', "ixxx" },
{0xC870535A, &WrapI_IUUU<sceNpMatching2LeaveRoom>, "sceNpMatching2LeaveRoom", 'i', "ixxx" },
{0xAAD0946A, &WrapI_IUUUUU<sceNpMatching2JoinRoom>, "sceNpMatching2JoinRoom", 'i', "ixxxxx" },
{0x81C13E6D, &WrapI_IUUU<sceNpMatching2SearchRoom>, "sceNpMatching2SearchRoom", 'i', "ixxx" },
{0x55F7837F, &WrapI_IUUU<sceNpMatching2SendRoomChatMessage>, "sceNpMatching2SendRoomChatMessage", 'i', "ixxx" },
};
void Register_sceNpMatching2()
{
RegisterModule("sceNpMatching2", ARRAY_SIZE(sceNpMatching2), sceNpMatching2);
}
+254
View File
@@ -0,0 +1,254 @@
// 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
// 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();
+44 -5
View File
@@ -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<int, u32> 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>, "sceUtilityGamedataInstallAbort", 'i', "" },
{0X16D02AF0, &WrapI_U<sceUtilityNpSigninInitStart>, "sceUtilityNpSigninInitStart", 'i', "x" },
{0XE19C97D6, nullptr, "sceUtilityNpSigninShutdownStart", 'i', "" },
{0XE19C97D6, &WrapI_V<sceUtilityNpSigninShutdownStart>, "sceUtilityNpSigninShutdownStart", 'i', "" },
{0XF3FBC572, &WrapI_I<sceUtilityNpSigninUpdate>, "sceUtilityNpSigninUpdate", 'i', "i" },
{0X86ABDB1B, &WrapI_V<sceUtilityNpSigninGetStatus>, "sceUtilityNpSigninGetStatus", 'i', "" },
+1
View File
@@ -85,6 +85,7 @@ enum class UtilityDialogType {
SCREENSHOT,
GAMESHARING,
GAMEDATAINSTALL,
NPSIGNIN,
};
void __UtilityInit();
+131
View File
@@ -0,0 +1,131 @@
// 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", Draw::SEM_POSITION },
{ "vec2", "a_texcoord", Draw::SEM_TEXCOORD0 },
};
static const VaryingDef varyings[1] = {
{ "vec2", "v_texcoord", Draw::SEM_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<UniformDef>::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<UniformDef>::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 = 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::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter) {
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_(draw2DFs_ && draw2DVs_);
InputLayoutDesc desc = {
{
{ 16, false },
},
{
{ 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 },
{ 0, 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);
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, linearFilter ? &draw2DSamplerLinear_ : &draw2DSamplerNearest_);
draw_->DrawUP(verts, vertexCount);
}
+9
View File
@@ -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;
};
+10
View File
@@ -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.
+210 -13
View File
@@ -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);
}
@@ -469,7 +471,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..?)
}
@@ -581,15 +583,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 +696,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.
@@ -975,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();
@@ -1457,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.
@@ -2388,6 +2389,7 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb,
}
}
draw_->InvalidateCachedState();
textureCache_->ForgetLastTexture();
RebindFramebuffer("RebindFramebuffer - ReadFramebufferToMemory");
}
@@ -2442,6 +2444,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);
@@ -2487,6 +2490,15 @@ void FramebufferManagerCommon::DeviceLost() {
DoRelease(reinterpretVBuf_);
DoRelease(reinterpretSampler_);
DoRelease(reinterpretVS_);
DoRelease(stencilUploadFs_);
DoRelease(stencilUploadVs_);
DoRelease(stencilUploadSampler_);
DoRelease(stencilUploadPipeline_);
DoRelease(draw2DPipelineLinear_);
DoRelease(draw2DSamplerNearest_);
DoRelease(draw2DSamplerLinear_);
DoRelease(draw2DVs_);
DoRelease(draw2DFs_);
presentation_->DeviceLost();
draw_ = nullptr;
}
@@ -2495,3 +2507,188 @@ 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, (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);
}
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;
}
// 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;
}
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;
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 {
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);
}
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);
}
+26 -10
View File
@@ -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.
@@ -30,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,
@@ -165,7 +164,6 @@ enum BindFramebufferColorFlags {
enum DrawTextureFlags {
DRAWTEX_NEAREST = 0,
DRAWTEX_LINEAR = 1,
DRAWTEX_KEEP_STENCIL_ALPHA = 4,
DRAWTEX_TO_BACKBUFFER = 8,
};
@@ -253,7 +251,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 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).
@@ -329,7 +327,6 @@ public:
SetColorUpdated(currentRenderVfb_, skipDrawReason);
}
}
void SetRenderSize(VirtualFramebuffer *vfb);
void SetSafeSize(u16 w, u16 h);
virtual void Resized();
@@ -355,8 +352,9 @@ 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 Bind2DShader() = 0;
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 DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter);
bool UpdateSize();
@@ -364,7 +362,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);
@@ -442,7 +445,6 @@ protected:
int pixelHeight_;
int bloomHack_ = 0;
bool needGLESRebinds_ = false;
Draw::DataFormat preferredPixelsFormat_ = Draw::DataFormat::R8G8B8A8_UNORM;
struct TempFBOInfo {
@@ -467,4 +469,18 @@ 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;
// Draw2D pipelines
Draw::Pipeline *draw2DPipelineLinear_ = nullptr;
Draw::SamplerState *draw2DSamplerLinear_ = nullptr;
Draw::SamplerState *draw2DSamplerNearest_ = nullptr;
Draw::ShaderModule *draw2DVs_ = nullptr;
Draw::ShaderModule *draw2DFs_ = nullptr;
};
+1 -3
View File
@@ -807,13 +807,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;
}
+5 -3
View File
@@ -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.
@@ -79,9 +80,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;
}
+282 -3
View File
@@ -15,9 +15,17 @@
// 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 "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/Reporting.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "GPU/Common/TextureCacheCommon.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 +36,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 +47,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 +57,274 @@ u8 StencilBits8888(const u8 *ptr8, u32 numPixels) {
return bits >> 24;
}
struct StencilUB {
float stencilValue;
};
const UniformBufferDesc stencilUBDesc { sizeof(StencilUB), {
{ "stencilValue", -1, 0, UniformType::FLOAT1, 0 },
} };
// TODO: Merge this with UniformBufferDesc
static const UniformDef uniforms[1] = {
{ "float", "stencilValue", 0 },
};
static const InputDef inputs[1] = {
{ "vec2", "a_position", Draw::SEM_POSITION, }
};
static const VaryingDef varyings[1] = {
{ "vec2", "v_texcoord", Draw::SEM_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 = 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");
if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) {
writer.C(" gl_FragDepth = gl_FragCoord.z;\n");
}
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(lang.vertexIndex ? Slice<InputDef>::empty() : inputs, Slice<UniformDef>::empty(), varyings);
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);
}
bool FramebufferManagerCommon::PerformStencilUpload(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");
}
// 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;
}
shaderManager_->DirtyLastShader();
textureCache_->ForgetLastTexture();
if (!stencilUploadPipeline_) {
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_);
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_);
delete[] fsCode;
delete[] vsCode;
rasterNoCull->Release();
blendOff->Release();
stencilWrite->Release();
inputLayout->Release();
SamplerStateDesc descNearest{};
stencilUploadSampler_ = draw_->CreateSamplerState(descNearest);
}
// Fullscreen triangle coordinates.
static const float positions[6] = {
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
};
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
// 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;
}
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");
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;
}
+5 -3
View File
@@ -2,6 +2,8 @@
#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);
#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);
-250
View File
@@ -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"
@@ -46,97 +43,27 @@
#include <emmintrin.h>
#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<float4> 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<uint8_t> 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_));
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;
}
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++) {
@@ -151,11 +78,6 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() {
stencilUploadInputLayout_->Release();
if (stencilValueBuffer_)
stencilValueBuffer_->Release();
if (nullTextureView_)
nullTextureView_->Release();
if (nullTexture_)
nullTexture_->Release();
}
void FramebufferManagerD3D11::SetTextureCache(TextureCacheD3D11 *tc) {
@@ -170,78 +92,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) {
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},
};
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];
}
}
float invDestW = 1.0f / (destW * 0.5f);
float invDestH = 1.0f / (destH * 0.5f);
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);
}
if (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;
}
}
// 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);
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);
}
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;
@@ -267,106 +117,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;
struct Vtx {
float x, y, z, u, v;
};
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);
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_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.
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) {
-22
View File
@@ -39,49 +39,27 @@ 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();
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
// TODO: Remove
ID3D11Buffer *GetDynamicQuadBuffer() {
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);
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_;
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;
ID3D11InputLayout *stencilUploadInputLayout_ = nullptr;
ID3D11Buffer *stencilValueBuffer_ = nullptr;
ID3D11DepthStencilState *stencilMaskStates_[256]{};
ID3D11Texture2D *nullTexture_ = nullptr;
ID3D11ShaderResourceView *nullTextureView_ = nullptr;
};
-1
View File
@@ -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;
-245
View File
@@ -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 <d3d11.h>
#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<float4> 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<uint8_t> 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;
}
-194
View File
@@ -47,97 +47,20 @@
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;
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;
}
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();
}
void FramebufferManagerDX9::SetTextureCache(TextureCacheDX9 *tc) {
@@ -152,72 +75,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);
device_->SetVertexShader(pFramebufferVertexShader);
}
LPDIRECT3DSURFACE9 FramebufferManagerDX9::GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface, VirtualFramebuffer *vfb) {
D3DSURFACE_DESC desc = {};
HRESULT hr = similarSurface->GetDesc(&desc);
@@ -249,57 +106,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;
+1 -18
View File
@@ -42,14 +42,11 @@ 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;
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;
@@ -59,12 +56,8 @@ public:
LPDIRECT3DSURFACE9 GetOffscreenSurface(D3DFORMAT fmt, u32 w, u32 h);
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);
@@ -73,16 +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 {
LPDIRECT3DSURFACE9 surface;
int last_frame_used;
@@ -91,4 +74,4 @@ private:
std::unordered_map<u64, OffscreenSurface> offscreenSurfaces_;
};
};
}
-259
View File
@@ -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 <d3d9.h>
#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
-10
View File
@@ -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]{};
+8 -255
View File
@@ -39,77 +39,20 @@
#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;
}
)";
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<GLRShader *> 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<GLRProgram::UniformLocQuery> queries;
queries.push_back({ &u_draw2d_tex, "u_tex" });
std::vector<GLRProgram::Initializer> initializers;
initializers.push_back({ &u_draw2d_tex, 0 });
std::vector<GLRProgram::Semantic> 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)
{
needBackBufferYSwap_ = true;
needGLESRebinds_ = true;
presentation_->SetLanguage(draw_->GetShaderLanguageDesc().shaderLanguage);
CreateDeviceObjects();
}
FramebufferManagerGLES::~FramebufferManagerGLES() {
delete[] convBuf_;
}
void FramebufferManagerGLES::Init() {
FramebufferManagerCommon::Init();
CompileDraw2DProgram();
}
void FramebufferManagerGLES::SetTextureCache(TextureCacheGLES *tc) {
@@ -125,118 +68,6 @@ void FramebufferManagerGLES::SetDrawEngine(DrawEngineGLES *td) {
drawEngine_ = td;
}
void FramebufferManagerGLES::CreateDeviceObjects() {
CompileDraw2DProgram();
std::vector<GLRInputLayout::Entry> 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 (stencilUploadProgram_) {
render_->DeleteProgram(stencilUploadProgram_);
stencilUploadProgram_ = nullptr;
}
if (depthDownloadProgram_) {
render_->DeleteProgram(depthDownloadProgram_);
depthDownloadProgram_ = nullptr;
}
}
FramebufferManagerGLES::~FramebufferManagerGLES() {
DestroyDeviceObjects();
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");
@@ -249,98 +80,20 @@ 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 = gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT);
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 (gstate_c.Supports(GPU_SUPPORTS_COPY_IMAGE)) {
// 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: Move this workaround out into thin3d, 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() {
}
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() {
-29
View File
@@ -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;
@@ -50,23 +47,12 @@ public:
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
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:
void CreateDeviceObjects();
void DestroyDeviceObjects();
void Bind2DShader() override;
void CompileDraw2DProgram();
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
GLRenderManager *render_;
@@ -74,26 +60,11 @@ private:
u8 *convBuf_ = nullptr;
u32 convBufSize_ = 0;
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;
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;
};
-7
View File
@@ -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;
+1 -1
View File
@@ -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.
+2 -9
View File
@@ -338,6 +338,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\ext\xbrz\xbrz.h" />
<ClInclude Include="Common\Draw2D.h" />
<ClInclude Include="Common\ReinterpretFramebuffer.h" />
<ClInclude Include="Common\DepalettizeShaderCommon.h" />
<ClInclude Include="Common\DrawEngineCommon.h" />
@@ -459,6 +460,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\ext\xbrz\xbrz.cpp" />
<ClCompile Include="Common\Draw2D.cpp" />
<ClCompile Include="Common\ReinterpretFramebuffer.cpp" />
<ClCompile Include="Common\DepalettizeShaderCommon.cpp" />
<ClCompile Include="Common\DrawEngineCommon.cpp" />
@@ -513,7 +515,6 @@
<ClCompile Include="D3D11\GPU_D3D11.cpp" />
<ClCompile Include="D3D11\ShaderManagerD3D11.cpp" />
<ClCompile Include="D3D11\StateMappingD3D11.cpp" />
<ClCompile Include="D3D11\StencilBufferD3D11.cpp" />
<ClCompile Include="D3D11\TextureCacheD3D11.cpp" />
<ClCompile Include="Debugger\Breakpoints.cpp" />
<ClCompile Include="Debugger\Debugger.cpp" />
@@ -525,7 +526,6 @@
<ClCompile Include="Directx9\GPU_DX9.cpp" />
<ClCompile Include="Directx9\ShaderManagerDX9.cpp" />
<ClCompile Include="Directx9\StateMappingDX9.cpp" />
<ClCompile Include="Directx9\StencilBufferDX9.cpp" />
<ClCompile Include="Directx9\TextureCacheDX9.cpp" />
<ClCompile Include="Directx9\DrawEngineDX9.cpp" />
<ClCompile Include="GeDisasm.cpp" />
@@ -572,12 +572,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GLES\StencilBufferGLES.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GLES\TextureCacheGLES.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
@@ -616,7 +610,6 @@
<ClCompile Include="Vulkan\PipelineManagerVulkan.cpp" />
<ClCompile Include="Vulkan\ShaderManagerVulkan.cpp" />
<ClCompile Include="Vulkan\StateMappingVulkan.cpp" />
<ClCompile Include="Vulkan\StencilBufferVulkan.cpp" />
<ClCompile Include="Vulkan\TextureCacheVulkan.cpp" />
<ClCompile Include="Vulkan\VulkanUtil.cpp" />
</ItemGroup>
+6 -12
View File
@@ -264,6 +264,9 @@
<ClInclude Include="Software\BinManager.h">
<Filter>Software</Filter>
</ClInclude>
<ClInclude Include="Common\Draw2D.h">
<Filter>Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@@ -356,9 +359,6 @@
<ClCompile Include="Common\SplineCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Directx9\StencilBufferDX9.cpp">
<Filter>DirectX9</Filter>
</ClCompile>
<ClCompile Include="Common\DepalettizeShaderCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
@@ -416,9 +416,6 @@
<ClCompile Include="GLES\StateMappingGLES.cpp">
<Filter>GLES</Filter>
</ClCompile>
<ClCompile Include="GLES\StencilBufferGLES.cpp">
<Filter>GLES</Filter>
</ClCompile>
<ClCompile Include="GLES\DepalettizeShaderGLES.cpp">
<Filter>GLES</Filter>
</ClCompile>
@@ -455,9 +452,6 @@
<ClCompile Include="D3D11\D3D11Util.cpp">
<Filter>D3D11</Filter>
</ClCompile>
<ClCompile Include="D3D11\StencilBufferD3D11.cpp">
<Filter>D3D11</Filter>
</ClCompile>
<ClCompile Include="Common\ShaderCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
@@ -473,9 +467,6 @@
<ClCompile Include="Debugger\Record.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Vulkan\StencilBufferVulkan.cpp">
<Filter>Vulkan</Filter>
</ClCompile>
<ClCompile Include="Common\StencilCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
@@ -530,6 +521,9 @@
<ClCompile Include="Software\BinManager.cpp">
<Filter>Software</Filter>
</ClCompile>
<ClCompile Include="Common\Draw2D.cpp">
<Filter>Common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<FxCompile Include="..\assets\shaders\tex_4xbrz.csh">
+1 -1
View File
@@ -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;
+2 -4
View File
@@ -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),
-217
View File
@@ -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,55 +70,6 @@ void FramebufferManagerVulkan::SetDrawEngine(DrawEngineVulkan *td) {
drawEngine_ = 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) {
int mask = 0;
// The Clear detection takes care of doing a regular draw instead if separate masking
@@ -170,143 +92,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_);
}
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();
}
@@ -315,11 +100,9 @@ void FramebufferManagerVulkan::EndFrame() {
}
void FramebufferManagerVulkan::DeviceLost() {
DestroyDeviceObjects();
FramebufferManagerCommon::DeviceLost();
}
void FramebufferManagerVulkan::DeviceRestore(Draw::DrawContext *draw) {
FramebufferManagerCommon::DeviceRestore(draw);
InitDeviceObjects();
}
-37
View File
@@ -41,10 +41,6 @@ public:
void SetShaderManager(ShaderManagerVulkan *sm);
void SetDrawEngine(DrawEngineVulkan *td);
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();
@@ -52,44 +48,11 @@ 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);
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();
// Used to keep track of command buffers here but have moved all that into Thin3D.
VulkanPushBuffer *push_;
enum {
MAX_COMMAND_BUFFERS = 32,
};
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_;
};
-7
View File
@@ -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;
@@ -333,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_);
-229
View File
@@ -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;
}
+2 -1
View File
@@ -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;
}
+4
View File
@@ -415,6 +415,7 @@
<ClInclude Include="..\..\Core\Dialog\PSPGamedataInstallDialog.h" />
<ClInclude Include="..\..\Core\Dialog\PSPMsgDialog.h" />
<ClInclude Include="..\..\Core\Dialog\PSPNetconfDialog.h" />
<ClInclude Include="..\..\Core\Dialog\PSPNpSigninDialog.h" />
<ClInclude Include="..\..\Core\Dialog\PSPOskDialog.h" />
<ClInclude Include="..\..\Core\Dialog\PSPPlaceholderDialog.h" />
<ClInclude Include="..\..\Core\Dialog\PSPSaveDialog.h" />
@@ -440,6 +441,7 @@
<ClInclude Include="..\..\Core\FileSystems\VirtualDiscFileSystem.h" />
<ClInclude Include="..\..\Core\Font\PGF.h" />
<ClInclude Include="..\..\Core\HDRemaster.h" />
<ClInclude Include="..\..\Core\HLE\sceNp2.h" />
<ClInclude Include="..\..\Core\Instance.h" />
<ClInclude Include="..\..\Core\HLE\FunctionWrappers.h" />
<ClInclude Include="..\..\Core\HLE\HLE.h" />
@@ -650,6 +652,7 @@
<ClCompile Include="..\..\Core\Dialog\PSPGamedataInstallDialog.cpp" />
<ClCompile Include="..\..\Core\Dialog\PSPMsgDialog.cpp" />
<ClCompile Include="..\..\Core\Dialog\PSPNetconfDialog.cpp" />
<ClCompile Include="..\..\Core\Dialog\PSPNpSigninDialog.cpp" />
<ClCompile Include="..\..\Core\Dialog\PSPOskDialog.cpp" />
<ClCompile Include="..\..\Core\Dialog\PSPPlaceholderDialog.cpp" />
<ClCompile Include="..\..\Core\Dialog\PSPSaveDialog.cpp" />
@@ -675,6 +678,7 @@
<ClCompile Include="..\..\Core\FileSystems\VirtualDiscFileSystem.cpp" />
<ClCompile Include="..\..\Core\Font\PGF.cpp" />
<ClCompile Include="..\..\Core\HDRemaster.cpp" />
<ClCompile Include="..\..\Core\HLE\sceNp2.cpp" />
<ClCompile Include="..\..\Core\Instance.cpp" />
<ClCompile Include="..\..\Core\HLE\HLE.cpp" />
<ClCompile Include="..\..\Core\HLE\HLEHelperThread.cpp" />
+12
View File
@@ -539,6 +539,9 @@
<ClCompile Include="..\..\Core\Dialog\PSPNetconfDialog.cpp">
<Filter>Dialog</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\Dialog\PSPNpSigninDialog.cpp">
<Filter>Dialog</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\Dialog\PSPOskDialog.cpp">
<Filter>Dialog</Filter>
</ClCompile>
@@ -1112,6 +1115,9 @@
<ClCompile Include="..\..\Core\ThreadPools.cpp" />
<ClCompile Include="..\..\Core\ControlMapper.cpp" />
<ClCompile Include="..\..\Core\KeyMapDefaults.cpp" />
<ClCompile Include="..\..\Core\HLE\sceNp2.cpp">
<Filter>HLE</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@@ -1539,6 +1545,9 @@
<ClInclude Include="..\..\Core\Dialog\PSPNetconfDialog.h">
<Filter>Dialog</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\Dialog\PSPNpSigninDialog.h">
<Filter>Dialog</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\Dialog\PSPOskDialog.h">
<Filter>Dialog</Filter>
</ClInclude>
@@ -1755,6 +1764,9 @@
<ClInclude Include="..\..\Core\ThreadPools.h" />
<ClInclude Include="..\..\Core\ControlMapper.h" />
<ClInclude Include="..\..\Core\KeyMapDefaults.h" />
<ClInclude Include="..\..\Core\HLE\sceNp2.h">
<Filter>HLE</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\ext\gason\LICENSE">
+2 -1
View File
@@ -380,6 +380,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\GPU\Common\DepalettizeShaderCommon.h" />
<ClInclude Include="..\..\GPU\Common\Draw2D.h" />
<ClInclude Include="..\..\GPU\Common\DrawEngineCommon.h" />
<ClInclude Include="..\..\GPU\Common\FragmentShaderGenerator.h" />
<ClInclude Include="..\..\GPU\Common\FramebufferManagerCommon.h" />
@@ -439,6 +440,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\GPU\Common\DepalettizeShaderCommon.cpp" />
<ClCompile Include="..\..\GPU\Common\Draw2D.cpp" />
<ClCompile Include="..\..\GPU\Common\DrawEngineCommon.cpp" />
<ClCompile Include="..\..\GPU\Common\FragmentShaderGenerator.cpp" />
<ClCompile Include="..\..\GPU\Common\FramebufferManagerCommon.cpp" />
@@ -470,7 +472,6 @@
<ClCompile Include="..\..\GPU\D3D11\GPU_D3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\ShaderManagerD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\StateMappingD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\StencilBufferD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\TextureCacheD3D11.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Breakpoints.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Debugger.cpp" />
+2 -1
View File
@@ -30,7 +30,6 @@
<ClCompile Include="..\..\GPU\D3D11\GPU_D3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\ShaderManagerD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\StateMappingD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\StencilBufferD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\TextureCacheD3D11.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Breakpoints.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Debugger.cpp" />
@@ -58,6 +57,7 @@
<ClCompile Include="..\..\GPU\Common\FragmentShaderGenerator.cpp" />
<ClCompile Include="..\..\GPU\Common\VertexShaderGenerator.cpp" />
<ClCompile Include="..\..\GPU\Common\ReinterpretFramebuffer.cpp" />
<ClCompile Include="..\..\GPU\Common\Draw2D.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\GPU\Common\DepalettizeShaderCommon.h" />
@@ -117,5 +117,6 @@
<ClInclude Include="..\..\GPU\Common\FragmentShaderGenerator.h" />
<ClInclude Include="..\..\GPU\Common\VertexShaderGenerator.h" />
<ClInclude Include="..\..\GPU\Common\ReinterpretFramebuffer.h" />
<ClInclude Include="..\..\GPU\Common\Draw2D.h" />
</ItemGroup>
</Project>
+9 -2
View File
@@ -184,14 +184,14 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<PackageCertificateKeyFile>PPSSPP_UWP_TemporaryKey.pfx</PackageCertificateKeyFile>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<AppxBundle>Never</AppxBundle>
<PackageCertificateThumbprint>b5e422213fb26042db3327f1102c4f9b86c27b1c</PackageCertificateThumbprint>
<PackageCertificateThumbprint>169879A9D7A20F22B0DD435921035E3E6D5996A4</PackageCertificateThumbprint>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppInstallerUpdateFrequency>1</AppInstallerUpdateFrequency>
<AppInstallerCheckForUpdateFrequency>OnApplicationRun</AppInstallerCheckForUpdateFrequency>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Link>
@@ -596,6 +596,13 @@
<DeploymentContent>true</DeploymentContent>
<FileType>Document</FileType>
</Image>
<Image Include="Content\asciifont_atlas.zim">
<DeploymentContent>true</DeploymentContent>
<FileType>Document</FileType>
</Image>
<None Include="Content\asciifont_atlas.meta">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="..\assets\ppge_atlas.meta">
<DeploymentContent>true</DeploymentContent>
</None>
+10 -5
View File
@@ -88,9 +88,6 @@
<Image Include="Content\7z.png">
<Filter>Content</Filter>
</Image>
<Image Include="Content\rargray.png">
<Filter>Content</Filter>
</Image>
<Image Include="Content\unknown.png">
<Filter>Content</Filter>
</Image>
@@ -103,12 +100,17 @@
<Image Include="AssetsGold\StoreLogo.scale-100.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Content\rargray.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Content\asciifont_atlas.zim">
<Filter>Content</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest" />
</ItemGroup>
<ItemGroup>
<None Include="UWP_TemporaryKey.pfx" />
<None Include="Content\compat.ini">
<Filter>Content</Filter>
</None>
@@ -365,6 +367,9 @@
<None Include="..\assets\themes\defaultthemes.ini">
<Filter>Content\themes</Filter>
</None>
<None Include="Content\asciifont_atlas.meta">
<Filter>Content</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Text Include="Content\gamecontrollerdb.txt">
@@ -376,4 +381,4 @@
<Filter>Content</Filter>
</Font>
</ItemGroup>
</Project>
</Project>
+3 -2
View File
@@ -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 \
@@ -320,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 \
@@ -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 \
@@ -440,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 \
@@ -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 \
+3 -4
View File
@@ -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 \
@@ -369,7 +370,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 \
@@ -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 \
@@ -546,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 \
@@ -732,7 +734,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 +748,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 +758,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
+67 -13
View File
@@ -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"
@@ -89,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<uint32_t> 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;
@@ -111,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;
}
@@ -159,6 +160,8 @@ const char *ShaderLanguageToString(ShaderLanguage lang) {
}
bool TestReinterpretShaders() {
Draw::Bugs bugs;
ShaderLanguage languages[] = {
#if PPSSPP_PLATFORM(WINDOWS)
ShaderLanguage::HLSL_D3D11,
@@ -183,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;
@@ -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,8 +210,7 @@ bool TestReinterpretShaders() {
printf("Failed!\n%s\n", buffer);
failed = true;
} else {
std::string errorMessage;
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;
@@ -217,8 +220,55 @@ 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], 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;
} else {
printf("===\n%s\n===\n", buffer);
}
GenerateStencilVs(buffer, desc);
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;
} else {
printf("===\n%s\n===\n", buffer);
}
}
delete[] buffer;
return !failed;
}
@@ -281,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;
}
@@ -343,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;
}
@@ -369,7 +419,7 @@ bool TestShaderGenerators() {
init_glslang();
#endif
if (!TestFragmentShaders()) {
if (!TestStencilShaders()) {
return false;
}
@@ -377,6 +427,10 @@ bool TestShaderGenerators() {
return false;
}
if (!TestFragmentShaders()) {
return false;
}
if (!TestVertexShaders()) {
return false;
}