mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-13 06:20:26 +02:00
Merge branch 'master' into feature_openxr_6dof
This commit is contained in:
commit
5f377f82eb
63 files changed
+2724
-2047
No files matched your search
+6
-4
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
@@ -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(¶ms, paramAddr, size);
|
||||
serviceId = Memory::GetCharPointer(params.serviceIdAddr);
|
||||
npServiceId = Memory::GetCharPointer(params.serviceIdAddr);
|
||||
|
||||
INFO_LOG(HLE, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor);
|
||||
INFO_LOG(HLE, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr));
|
||||
INFO_LOG(HLE, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr));
|
||||
INFO_LOG(HLE, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr));
|
||||
INFO_LOG(SCENET, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor);
|
||||
INFO_LOG(SCENET, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr));
|
||||
INFO_LOG(SCENET, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr));
|
||||
INFO_LOG(SCENET, "%s - Consumed Count: %d", __FUNCTION__, params.consumedCount);
|
||||
INFO_LOG(SCENET, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr));
|
||||
|
||||
u32 retval = 0;
|
||||
if (params.size >= 32 && params.ticketCbAddr != 0) {
|
||||
@@ -254,12 +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
@@ -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();
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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', "" },
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ enum class UtilityDialogType {
|
||||
SCREENSHOT,
|
||||
GAMESHARING,
|
||||
GAMEDATAINSTALL,
|
||||
NPSIGNIN,
|
||||
};
|
||||
|
||||
void __UtilityInit();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
@@ -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]{};
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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_;
|
||||
};
|
||||
@@ -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_);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
@@ -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
@@ -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>
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user