diff --git a/CMakeLists.txt b/CMakeLists.txt index dad85680cb..8f9f5ee4e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1356,6 +1356,8 @@ set(GPU_SOURCES GPU/Common/ShaderUniforms.h GPU/Common/ShaderCommon.cpp GPU/Common/ShaderCommon.h + GPU/Common/ShaderWriter.cpp + GPU/Common/ShaderWriter.h GPU/Common/ShaderTranslation.cpp GPU/Common/ShaderTranslation.h GPU/Common/SplineCommon.cpp diff --git a/Common/Data/Encoding/Utf8.cpp b/Common/Data/Encoding/Utf8.cpp index 8e3bb0f05d..f3c2b1e223 100644 --- a/Common/Data/Encoding/Utf8.cpp +++ b/Common/Data/Encoding/Utf8.cpp @@ -450,6 +450,12 @@ void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &sou MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size)); } +void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const char *source) { + int len = (int)strlen(source) + 1; // include trailing zero + int size = (int)MultiByteToWideChar(CP_UTF8, 0, source, len, NULL, 0); + MultiByteToWideChar(CP_UTF8, 0, source, len, dest, std::min((int)destSize, size)); +} + std::wstring ConvertUTF8ToWString(const std::string &source) { int len = (int)source.size(); int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); diff --git a/Common/Data/Encoding/Utf8.h b/Common/Data/Encoding/Utf8.h index 9d04a788a0..b954ef5371 100644 --- a/Common/Data/Encoding/Utf8.h +++ b/Common/Data/Encoding/Utf8.h @@ -83,6 +83,7 @@ bool UTF8StringHasNonASCII(const char *utf8string); std::string ConvertWStringToUTF8(const std::wstring &wstr); std::string ConvertWStringToUTF8(const wchar_t *wstr); void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source); +void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const char *source); std::wstring ConvertUTF8ToWString(const std::string &source); #else diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index e9bdf76103..b70848cb28 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -213,7 +213,11 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan } } -void VulkanRenderManager::CreateBackbuffers() { +bool VulkanRenderManager::CreateBackbuffers() { + if (!vulkan_->GetSwapchain()) { + ERROR_LOG(G3D, "No swapchain - can't create backbuffers"); + return false; + } VkResult res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, nullptr); _dbg_assert_(res == VK_SUCCESS); @@ -222,7 +226,7 @@ void VulkanRenderManager::CreateBackbuffers() { if (res != VK_SUCCESS) { ERROR_LOG(G3D, "vkGetSwapchainImagesKHR failed"); delete[] swapchainImages; - return; + return false; } VkCommandBuffer cmdInit = GetInitCmd(); @@ -283,6 +287,7 @@ void VulkanRenderManager::CreateBackbuffers() { INFO_LOG(G3D, "Starting Vulkan submission thread (threadInitFrame_ = %d)", vulkan_->GetCurFrame()); thread_ = std::thread(&VulkanRenderManager::ThreadFunc, this); } + return true; } void VulkanRenderManager::StopThread() { diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 19fb6b1fb3..1914f5214c 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -289,7 +289,7 @@ public: return renderStepOffset_ + (int)steps_.size(); } - void CreateBackbuffers(); + bool CreateBackbuffers(); void DestroyBackbuffers(); bool HasBackbuffers() { diff --git a/GPU/Common/ColorReinterpret.cpp b/GPU/Common/ColorReinterpret.cpp new file mode 100644 index 0000000000..3699d2f8aa --- /dev/null +++ b/GPU/Common/ColorReinterpret.cpp @@ -0,0 +1,49 @@ +#include + +#include "GPU/Common/ColorReinterpret.h" +#include "GPU/Common/ShaderWriter.h" + +// TODO: We could have an option to preserve any extra color precision. But gonna start without it. +// Requires full size integer math. +bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang) { + if (!lang.bitwiseOps) { + return false; + } + ShaderWriter writer(buffer, lang, ShaderStage::Fragment); + + switch (from) { + case GE_FORMAT_4444: + writer.W(" uint color = uint(in.r * 15.99) | (uint(in.g * 15.99) << 4) | (uint(in.b * 15.99) << 8) | (uint(in.a * 15.99) << 12);\n"); + break; + case GE_FORMAT_5551: + writer.W(" uint color = uint(in.r * 31.99) | (uint(in.g * 31.99) << 5) | (uint(in.b * 31.99) << 10);\n"); + writer.W(" if (in.a > 128.0) color |= 0x8000;\n"); + break; + case GE_FORMAT_565: + writer.W(" uint color = uint(in.r * 31.99) | (uint(in.g * 63.99) << 5) | (uint(in.b * 31.99) << 11);\n"); + break; + default: _assert_(false); + } + + switch (to) { + case GE_FORMAT_4444: + writer.W(" vec4 output = vec4(float(color & 0xF), float((color >> 4) & 0xF), float((color >> 8) & 0xF), float((color >> 12) & 0xF));\n"); + writer.W(" output *= 1.0 / 15.0;\n"); + break; + case GE_FORMAT_5551: + writer.W(" vec4 output = vec4(float(color & 0x1F), float((color >> 5) & 0x1F), float((color >> 10) & 0x1F), 0.0);\n"); + writer.W(" output.rgb *= 1.0 / 31.0;\n"); + writer.W(" output.a = float(color >> 15);\n"); + break; + case GE_FORMAT_565: + writer.W(" vec4 output = vec4(float(color & 0x1F), float((color >> 5) & 0x3F), float((color >> 11) & 0x1F), 1.0);\n"); + writer.W(" output.rb *= 1.0 / 31.0;\n"); + writer.W(" output.g *= 1.0 / 63.0;\n"); + break; + default: _assert_(false); + } + + writer.W("}"); + + return true; +} diff --git a/GPU/Common/ColorReinterpret.h b/GPU/Common/ColorReinterpret.h new file mode 100644 index 0000000000..c1ff33226a --- /dev/null +++ b/GPU/Common/ColorReinterpret.h @@ -0,0 +1,6 @@ +#pragma once + +#include "Common/Log.h" +#include "GPU/ge_constants.h" +#include "GPU/GPUCommon.h" +#include "GPU/Common/ShaderWriter.h" diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index bb51a14c36..cb55b2ad35 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -27,44 +27,11 @@ #include "GPU/Common/ShaderId.h" #include "GPU/Common/ShaderUniforms.h" #include "GPU/Common/FragmentShaderGenerator.h" +#include "GPU/Common/ShaderWriter.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" -#define WRITE p+=sprintf - -const char *vulkan_glsl_preamble_fs = -"#version 450\n" -"#extension GL_ARB_separate_shader_objects : enable\n" -"#extension GL_ARB_shading_language_420pack : enable\n" -"#extension GL_ARB_conservative_depth : enable\n" -"#extension GL_ARB_shader_image_load_store : enable\n" -"#define splat3(x) vec3(x)\n" -"#define lowp\n" -"#define mediump\n" -"#define highp\n" -"#define DISCARD discard\n" -"\n"; - -const char *hlsl_preamble_fs = -"#define vec2 float2\n" -"#define vec3 float3\n" -"#define vec4 float4\n" -"#define uvec3 uint3\n" -"#define ivec3 int3\n" -"#define ivec4 int4\n" -"#define mat4 float4x4\n" -"#define mat3x4 float4x3\n" // note how the conventions are backwards -"#define splat3(x) float3(x, x, x)\n" -"#define mix lerp\n" -"#define mod(x, y) fmod(x, y)\n"; - -const char *hlsl_d3d11_preamble_fs = -"#define DISCARD discard\n" -"#define DISCARD_BELOW(x) clip(x);\n"; -const char *hlsl_d3d9_preamble_fs = -"#define DISCARD clip(-1)\n" -"#define DISCARD_BELOW(x) clip(x)\n"; - +#define WRITE(p, ...) p.F(__VA_ARGS__) bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, uint64_t *uniformMask, std::string *errorString) { *uniformMask = 0; @@ -83,45 +50,21 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu ReplaceAlphaType stencilToAlpha = static_cast(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)); - char *p = buffer; - - switch (compat.shaderLanguage) { - case ShaderLanguage::GLSL_VULKAN: - WRITE(p, "%s", vulkan_glsl_preamble_fs); - break; - case ShaderLanguage::HLSL_D3D11: - WRITE(p, "%s", hlsl_preamble_fs); - WRITE(p, "%s", hlsl_d3d11_preamble_fs); - break; - case ShaderLanguage::HLSL_D3D9: - WRITE(p, "%s", hlsl_preamble_fs); - WRITE(p, "%s", hlsl_d3d9_preamble_fs); - break; - default: - // OpenGL - WRITE(p, "#version %d%s\n", compat.glslVersionNumber, compat.gles && compat.glslES30 ? " es" : ""); - WRITE(p, "#define DISCARD discard\n"); - + std::vector gl_exts; + if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) { - WRITE(p, "#extension GL_EXT_blend_func_extended : require\n"); + gl_exts.push_back("#extension GL_EXT_blend_func_extended : require"); } if (gl_extensions.EXT_gpu_shader4) { - WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); + gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); } if (compat.framebufferFetchExtension) { - WRITE(p, "%s\n", compat.framebufferFetchExtension); + gl_exts.push_back(compat.framebufferFetchExtension); } - if (!compat.gles) { - WRITE(p, "#define lowp\n"); - WRITE(p, "#define mediump\n"); - WRITE(p, "#define highp\n"); - } else { - WRITE(p, "precision lowp float;\n"); - } - - WRITE(p, "#define splat3(x) vec3(x)\n"); } + ShaderWriter p(buffer, compat, ShaderStage::Fragment, gl_exts.data(), gl_exts.size()); + bool lmode = id.Bit(FS_BIT_LMODE); bool doTexture = id.Bit(FS_BIT_DO_TEXTURE); bool enableFog = id.Bit(FS_BIT_ENABLE_FOG); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index cb656a35ef..502742c6a4 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -265,10 +265,13 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame if (v->fb_address == params.fb_address) { vfb = v; // Update fb stride in case it changed - if (vfb->fb_stride != params.fb_stride || vfb->format != params.fmt) { - vfbFormatChanged = true; + if (vfb->fb_stride != params.fb_stride) { vfb->fb_stride = params.fb_stride; + vfbFormatChanged = true; + } + if (vfb->format != params.fmt) { vfb->format = params.fmt; + vfbFormatChanged = true; } if (vfb->z_address == 0 && vfb->z_stride == 0 && params.z_stride != 0) { @@ -1087,7 +1090,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, shaderManager_->DirtyLastShader(); char tag[256]; - snprintf(tag, sizeof(tag), "%08x_%08x_%dx%d", vfb->fb_address, vfb->z_address, w, h); + snprintf(tag, sizeof(tag), "%08x_%08x_%dx%d_%s", vfb->fb_address, vfb->z_address, w, h, GeBufferFormatToString((GEBufferFormat)vfb->colorDepth)); vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth, tag }); if (old.fbo) { INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->format)); diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 44cd2f6b5f..ca3b69f5cb 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -55,7 +55,7 @@ struct VirtualFramebuffer { int fb_stride; int z_stride; - GEBufferFormat format; // virtual, right now they are all RGBA8888 + GEBufferFormat format; // virtual, in reality they are all RGBA8888 for better quality but we can reinterpret that as necessary // width/height: The detected size of the current framebuffer, in original PSP pixels. u16 width; @@ -424,4 +424,9 @@ protected: FBO_OLD_AGE = 5, FBO_OLD_USAGE_FLAG = 15, }; + + // Thin3D stuff for reinterpreting image data between the various 16-bit formats. + // Safe, not optimal - there might be input attachment tricks, etc, but we can't use them + // since we don't want N different implementations. + Draw::Pipeline *reinterpretFromTo_[3][3]; }; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 2d4da991c6..c359922085 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -411,7 +411,7 @@ void PresentationCommon::CreateDeviceObjects() { vdata_ = draw_->CreateBuffer(sizeof(Vertex) * 8, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); - // TODO: Use 4 and a strip? + // TODO: Use a triangle strip? Makes the UV rotation slightly more complex. idata_ = draw_->CreateBuffer(sizeof(uint16_t) * 6, BufferUsageFlag::DYNAMIC | BufferUsageFlag::INDEXDATA); uint16_t indexes[] = { 0, 1, 2, 0, 2, 3 }; draw_->UpdateBuffer(idata_, (const uint8_t *)indexes, 0, sizeof(indexes), Draw::UPDATE_DISCARD); diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h index 34594dfba7..e238bd9dc6 100644 --- a/GPU/Common/ShaderCommon.h +++ b/GPU/Common/ShaderCommon.h @@ -52,6 +52,11 @@ enum DebugShaderStringType { SHADER_STRING_STATS = 2, }; +enum class ShaderStage { + Vertex, + Fragment +}; + // Shared between the backends. Not all are necessarily used by each backend, but this lets us share // more code than before. enum : uint64_t { diff --git a/GPU/Common/ShaderWriter.cpp b/GPU/Common/ShaderWriter.cpp new file mode 100644 index 0000000000..323bd3b86c --- /dev/null +++ b/GPU/Common/ShaderWriter.cpp @@ -0,0 +1,124 @@ +#include "GPU/Common/ShaderWriter.h" + +const char *vulkan_glsl_preamble_fs = +"#version 450\n" +"#extension GL_ARB_separate_shader_objects : enable\n" +"#extension GL_ARB_shading_language_420pack : enable\n" +"#extension GL_ARB_conservative_depth : enable\n" +"#extension GL_ARB_shader_image_load_store : enable\n" +"#define splat3(x) vec3(x)\n" +"#define lowp\n" +"#define mediump\n" +"#define highp\n" +"#define DISCARD discard\n" +"\n"; + +const char *hlsl_preamble_fs = +"#define vec2 float2\n" +"#define vec3 float3\n" +"#define vec4 float4\n" +"#define uvec3 uint3\n" +"#define ivec3 int3\n" +"#define ivec4 int4\n" +"#define mat4 float4x4\n" +"#define mat3x4 float4x3\n" // note how the conventions are backwards +"#define splat3(x) float3(x, x, x)\n" +"#define mix lerp\n" +"#define mod(x, y) fmod(x, y)\n"; + +const char *hlsl_d3d11_preamble_fs = +"#define DISCARD discard\n" +"#define DISCARD_BELOW(x) clip(x);\n"; +const char *hlsl_d3d9_preamble_fs = +"#define DISCARD clip(-1)\n" +"#define DISCARD_BELOW(x) clip(x)\n"; + +const char *vulkan_glsl_preamble_vs = +"#version 450\n" +"#extension GL_ARB_separate_shader_objects : enable\n" +"#extension GL_ARB_shading_language_420pack : enable\n" +"#define mul(x, y) ((x) * (y))\n" +"#define splat3(x) vec3(x)\n" +"#define lowp\n" +"#define mediump\n" +"#define highp\n" +"\n"; + +const char *hlsl_preamble_vs = +"#define vec2 float2\n" +"#define vec3 float3\n" +"#define vec4 float4\n" +"#define ivec2 int2\n" +"#define ivec4 int4\n" +"#define mat4 float4x4\n" +"#define mat3x4 float4x3\n" // note how the conventions are backwards +"#define splat3(x) vec3(x, x, x)\n" +"#define lowp\n" +"#define mediump\n" +"#define highp\n" +"\n"; + +// Unsafe. But doesn't matter, we'll use big buffers for shader gen. +void ShaderWriter::F(const char *format, ...) { + va_list args; + va_start(args, format); + p_ += vsprintf(p_, format, args); + va_end(args); +} + +void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions) { + switch (lang_.shaderLanguage) { + case GLSL_VULKAN: + switch (stage_) { + case ShaderStage::Vertex: + W(vulkan_glsl_preamble_vs); + break; + case ShaderStage::Fragment: + W(vulkan_glsl_preamble_fs); + break; + } + break; + case HLSL_D3D11: + case HLSL_D3D9: + switch (stage_) { + case ShaderStage::Vertex: + W(hlsl_preamble_vs); + break; + case ShaderStage::Fragment: + W(hlsl_preamble_fs); + if (lang_.shaderLanguage == HLSL_D3D9) { + W(hlsl_d3d9_preamble_fs); + } else { + W(hlsl_d3d11_preamble_fs); + } + break; + } + break; + default: // OpenGL + F("#version %d%s\n", lang_.glslVersionNumber, lang_.gles && lang_.glslES30 ? " es" : ""); + switch (stage_) { + case ShaderStage::Fragment: + C("#define DISCARD discard\n"); + if (lang_.gles) { + C("precision lowp float;\n"); + } + break; + case ShaderStage::Vertex: + if (lang_.gles) { + C("precision highp float;\n"); + } + break; + } + for (size_t i = 0; i < num_gl_extensions; i++) { + F("%s\n", gl_extensions[i]); + } + if (!lang_.gles) { + C("#define lowp\n"); + C("#define mediump\n"); + C("#define highp\n"); + } + C("#define splat3(x) vec3(x)\n"); + C("#define mul(x, y) ((x) * (y))\n"); + break; + } +} diff --git a/GPU/Common/ShaderWriter.h b/GPU/Common/ShaderWriter.h new file mode 100644 index 0000000000..1d670be780 --- /dev/null +++ b/GPU/Common/ShaderWriter.h @@ -0,0 +1,51 @@ +#pragma once + +#include "Common/Log.h" +#include "GPU/ge_constants.h" +#include "GPU/GPUCommon.h" +#include "GPU/Common/ShaderCommon.h" + +// Helps generate a shader compatible with all backends. +// Using #defines and magic in this class, we partially define our own shader language that basically looks +// like GLSL, but has a few little oddities like splat3. + +class ShaderWriter { +public: + ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions, size_t num_gl_extensions) : p_(buffer), lang_(lang), stage_(stage) { + Preamble(gl_extensions, num_gl_extensions); + } + + // I tried to call all three write functions "W", but only MSVC + // managed to disentangle the ambiguities, so had to give up on that. + + // Assumes the input is zero-terminated. + // C : Copies a buffer directly to the stream. + template + void C(const char(&text)[T]) { + memcpy(p_, text, T); + p_ += T; + } + // W: Writes a zero-terminated string to the stream. + void W(const char *text) { + size_t len = strlen(text); + memcpy(p_, text, len + 1); + p_ += len; + } + + // F: Formats into the buffer. + void F(const char *format, ...); + + // void BeginMain(); + // void EndMain(); + + char *GetPos() { + return p_; + } + +private: + void Preamble(const char **gl_extensions, size_t num_gl_extensions); + + char *p_; + const ShaderLanguageDesc &lang_; + const ShaderStage stage_; +}; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 1c5c63cdce..fb84f0f6ec 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -471,11 +471,16 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { // No texture found, or changed (depending on entry). // Check for framebuffers. - TextureDefinition def{}; + TextureDefinition def; def.addr = texaddr; def.dim = dim; def.format = format; def.bufw = bufw; + def.swizzled = gstate.isTextureSwizzled(); + + if (texaddr == 0x40cc000) { + texaddr = texaddr; + } std::vector candidates = GetFramebufferCandidates(def, 0); if (candidates.size() > 0) { @@ -851,9 +856,11 @@ FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer( // NOTE: This check is okay because the first texture formats are the same as the buffer formats. if (entry.format != (GETextureFormat)framebuffer->format) { WARN_LOG_ONCE(diffFormat1, G3D, "Texturing from framebuffer with different formats %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(framebuffer->format)); - return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; - } else { return FramebufferMatchInfo{ FramebufferMatch::VALID }; + } else { + // TODO: Here we should either change the format of the framebuffer, reinterpreting it, + // or read from it while reinterpreting it. Not sure which is generally best. + return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } } else { // Apply to buffered mode only. @@ -1007,6 +1014,7 @@ bool TextureCacheCommon::SetOffsetTexture(u32 yOffset) { def.format = fmt; def.bufw = GetTextureBufw(0, texaddr, fmt); def.dim = gstate.getTextureDimension(0); + def.swizzled = gstate.isTextureSwizzled(); std::vector candidates = GetFramebufferCandidates(def, texaddrOffset); if (candidates.size() > 0) { diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 1b0300724b..7acfe3042c 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -98,6 +98,7 @@ struct TextureDefinition { GETextureFormat format; u32 dim; u32 bufw; + bool swizzled; }; diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 598c0ddbb8..da781e111a 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -26,12 +26,13 @@ #include "GPU/GPUState.h" #include "GPU/Common/ShaderId.h" #include "GPU/Common/ShaderUniforms.h" +#include "GPU/Common/ShaderWriter.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/VertexShaderGenerator.h" #undef WRITE -#define WRITE p+=sprintf +#define WRITE(p, ...) p.F(__VA_ARGS__) static const char * const boneWeightAttrDecl[9] = { "#ERROR#", @@ -122,30 +123,8 @@ static const char * const boneWeightDecl[9] = { "layout(location = 3) in vec4 w1;\nlayout(location = 4) in vec4 w2;\n", }; -const char *vulkan_glsl_preamble_vs = -"#version 450\n" -"#extension GL_ARB_separate_shader_objects : enable\n" -"#extension GL_ARB_shading_language_420pack : enable\n" -"#define mul(x, y) ((x) * (y))\n" -"#define splat3(x) vec3(x)\n" -"#define lowp\n" -"#define mediump\n" -"#define highp\n" -"\n"; - -const char *hlsl_preamble_vs = -"#define vec2 float2\n" -"#define vec3 float3\n" -"#define vec4 float4\n" -"#define ivec2 int2\n" -"#define ivec4 int4\n" -"#define mat4 float4x4\n" -"#define mat3x4 float4x3\n" // note how the conventions are backwards -"#define splat3(x) vec3(x, x, x)\n" -"#define lowp\n" -"#define mediump\n" -"#define highp\n" -"\n"; +extern const char *vulkan_glsl_preamble_vs; +extern const char *hlsl_preamble_vs; bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString) { *attrMask = 0; @@ -154,32 +133,13 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag bool highpFog = false; bool highpTexcoord = false; - char *p = buffer; - if (compat.shaderLanguage == GLSL_VULKAN) { - WRITE(p, "%s", vulkan_glsl_preamble_vs); - } else if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) { - WRITE(p, "%s", hlsl_preamble_vs); - } else if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { - if (compat.gles) { - // PowerVR needs highp to do the fog in MHU correctly. - // Others don't, and some can't handle highp in the fragment shader. - highpFog = (gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_BAD) ? true : false; - highpTexcoord = highpFog; - } - WRITE(p, "#version %d%s\n", compat.glslVersionNumber, compat.gles && compat.glslES30 ? " es" : ""); + std::vector gl_exts; + if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (gl_extensions.EXT_gpu_shader4) { - WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); + gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); } - if (compat.gles) { - WRITE(p, "precision highp float;\n"); - } else { - WRITE(p, "#define lowp\n"); - WRITE(p, "#define mediump\n"); - WRITE(p, "#define highp\n"); - } - WRITE(p, "#define splat3(x) vec3(x)\n"); - WRITE(p, "#define mul(x, y) ((x) * (y))\n"); } + ShaderWriter p(buffer, compat, ShaderStage::Vertex, gl_exts.data(), gl_exts.size()); bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); bool lmode = id.Bit(VS_BIT_LMODE); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index a989cf353f..4c3b92cdd7 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -496,6 +496,7 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { // Don't scale the PPGe texture. if (entry->addr > 0x05000000 && entry->addr < PSP_GetKernelMemoryEnd()) scaleFactor = 1; + if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) != 0 && scaleFactor != 1) { // Remember for later that we /wanted/ to scale this texture. entry->status |= TexCacheEntry::STATUS_TO_SCALE; diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 7a62854e6f..07adb059d8 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -492,9 +492,6 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { } } - // If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient. - Draw::DataFormat dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat()); - int scaleFactor = standardScaleFactor_; // Rachet down scale factor in low-memory mode. @@ -535,7 +532,10 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { texelsScaledThisFrame_ += w * h; } } - + + // If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient. + Draw::DataFormat dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat()); + // GLES2 doesn't have support for a "Max lod" which is critical as PSP games often // don't specify mips all the way down. As a result, we either need to manually generate // the bottom few levels or rely on OpenGL's autogen mipmaps instead, which might not @@ -546,10 +546,11 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { // NOTE: Since the level is not part of the cache key, we assume it never changes. u8 level = std::max(0, gstate.getTexLevelOffset16() / 16); LoadTextureLevel(*entry, replaced, level, scaleFactor, dstFmt); - } else + } else { LoadTextureLevel(*entry, replaced, 0, scaleFactor, dstFmt); + } - // Mipmapping only enable when texture scaling disable + // Mipmapping is only enabled when texture scaling is disabled. int texMaxLevel = 0; bool genMips = false; if (maxLevel > 0 && scaleFactor == 1) { diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 675602d6d5..bb7bb6980f 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -351,6 +351,7 @@ + @@ -488,6 +489,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 509e962588..c19594763f 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -270,6 +270,9 @@ Common + + Common + @@ -539,5 +542,8 @@ Common + + Common + \ No newline at end of file diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj index d5b5d3167e..aef600ae34 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj @@ -392,6 +392,7 @@ + @@ -449,6 +450,7 @@ + diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters index 12f33ec3af..c1e17c829d 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters @@ -57,6 +57,7 @@ + @@ -114,5 +115,6 @@ + \ No newline at end of file diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 61ca7784a2..16d293776d 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -21,6 +21,7 @@ #include #include "Common/Data/Text/Parsers.h" +#include "Common/Data/Encoding/Utf8.h" #include "Common/ColorConv.h" #include "Common/StringUtils.h" #include "Core/Config.h" @@ -274,10 +275,10 @@ void CGEDebugger::SetupPreviews() { } } -void CGEDebugger::DescribePrimaryPreview(const GPUgstate &state, wchar_t desc[256]) { +void CGEDebugger::DescribePrimaryPreview(const GPUgstate &state, char desc[256]) { if (showClut_) { // In this case, we're showing the texture here. - _snwprintf(desc, 256, L"Texture L%d: 0x%08x (%dx%d)", textureLevel_, state.getTextureAddress(textureLevel_), state.getTextureWidth(textureLevel_), state.getTextureHeight(textureLevel_)); + snprintf(desc, 256, "Texture L%d: 0x%08x (%dx%d)", textureLevel_, state.getTextureAddress(textureLevel_), state.getTextureWidth(textureLevel_), state.getTextureHeight(textureLevel_)); return; } @@ -285,24 +286,24 @@ void CGEDebugger::DescribePrimaryPreview(const GPUgstate &state, wchar_t desc[25 switch (PrimaryDisplayType(fbTabs->CurrentTabIndex())) { case PRIMARY_FRAMEBUF: - _snwprintf(desc, 256, L"Color: 0x%08x (%dx%d) fmt %i", state.getFrameBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight(), state.FrameBufFormat()); + snprintf(desc, 256, "Color: 0x%08x (%dx%d) fmt %s", state.getFrameBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight(), GeBufferFormatToString(state.FrameBufFormat())); break; case PRIMARY_DEPTHBUF: - _snwprintf(desc, 256, L"Depth: 0x%08x (%dx%d)", state.getDepthBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight()); + snprintf(desc, 256, "Depth: 0x%08x (%dx%d)", state.getDepthBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight()); break; case PRIMARY_STENCILBUF: - _snwprintf(desc, 256, L"Stencil: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight()); + snprintf(desc, 256, "Stencil: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight()); break; } } -void CGEDebugger::DescribeSecondPreview(const GPUgstate &state, wchar_t desc[256]) { +void CGEDebugger::DescribeSecondPreview(const GPUgstate &state, char desc[256]) { if (showClut_) { - _snwprintf(desc, 256, L"CLUT: 0x%08x (%d)", state.getClutAddress(), state.getClutPaletteFormat()); + snprintf(desc, 256, "CLUT: 0x%08x (%d)", state.getClutAddress(), state.getClutPaletteFormat()); } else { - _snwprintf(desc, 256, L"Texture L%d: 0x%08x (%dx%d)", textureLevel_, state.getTextureAddress(textureLevel_), state.getTextureWidth(textureLevel_), state.getTextureHeight(textureLevel_)); + snprintf(desc, 256, "Texture L%d: 0x%08x (%dx%d)", textureLevel_, state.getTextureAddress(textureLevel_), state.getTextureWidth(textureLevel_), state.getTextureHeight(textureLevel_)); } } @@ -414,9 +415,12 @@ void CGEDebugger::UpdatePrimaryPreview(const GPUgstate &state) { primaryWindow->SetFlags(flags); primaryWindow->Draw(primaryBuffer_->GetData(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight(), primaryBuffer_->GetFlipped(), fmt); - wchar_t desc[256]; + char desc[256]; + wchar_t w_desc[256]; DescribePrimaryPreview(state, desc); - SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, desc); + ConvertUTF8ToWString(w_desc, ARRAY_SIZE(w_desc), desc); + + SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, w_desc); } else if (primaryWindow != nullptr) { primaryWindow->Clear(); primaryBuffer_ = nullptr; @@ -452,9 +456,11 @@ void CGEDebugger::UpdateSecondPreview(const GPUgstate &state) { secondWindow->Draw(secondBuffer_->GetData(), secondBuffer_->GetStride(), secondBuffer_->GetHeight(), secondBuffer_->GetFlipped(), fmt); } - wchar_t desc[256]; + char desc[256]; DescribeSecondPreview(state, desc); - SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, desc); + wchar_t w_desc[256]; + ConvertUTF8ToWString(w_desc, ARRAY_SIZE(w_desc), desc); + SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, w_desc); } else if (secondWindow != nullptr) { secondWindow->Clear(); secondBuffer_ = nullptr; @@ -474,7 +480,7 @@ void CGEDebugger::PrimaryPreviewHover(int x, int y) { SetupPreviews(); - wchar_t desc[256] = {0}; + char desc[256] = {0}; if (!primaryWindow->HasTex()) { desc[0] = 0; @@ -491,7 +497,10 @@ void CGEDebugger::PrimaryPreviewHover(int x, int y) { DescribePixel(pix, primaryBuffer_->GetFormat(), x, y, desc); } - SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, desc); + wchar_t w_desc[256]; + ConvertUTF8ToWString(w_desc, ARRAY_SIZE(w_desc), desc); + + SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, w_desc); } void CGEDebugger::SecondPreviewHover(int x, int y) { @@ -499,7 +508,7 @@ void CGEDebugger::SecondPreviewHover(int x, int y) { return; } - wchar_t desc[256] = {0}; + char desc[256] = {0}; if (!secondWindow->HasTex()) { desc[0] = 0; @@ -519,11 +528,12 @@ void CGEDebugger::SecondPreviewHover(int x, int y) { DescribePixel(pix, secondBuffer_->GetFormat(), x, y, desc); } } - - SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, desc); + wchar_t w_desc[256]; + ConvertUTF8ToWString(w_desc, ARRAY_SIZE(w_desc), desc); + SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, w_desc); } -void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, wchar_t desc[256]) { +void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]) { switch (fmt) { case GPU_DBG_FORMAT_565: case GPU_DBG_FORMAT_565_REV: @@ -539,18 +549,18 @@ void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, break; case GPU_DBG_FORMAT_16BIT: - _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, pix, pix * (1.0f / 65535.0f)); + snprintf(desc, 256, "%d,%d: %d / %f", x, y, pix, pix * (1.0f / 65535.0f)); break; case GPU_DBG_FORMAT_8BIT: - _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, pix, pix * (1.0f / 255.0f)); + snprintf(desc, 256, "%d,%d: %d / %f", x, y, pix, pix * (1.0f / 255.0f)); break; case GPU_DBG_FORMAT_24BIT_8X: { DepthScaleFactors depthScale = GetDepthScaleFactors(); // These are only ever going to be depth values, so let's also show scaled to 16 bit. - _snwprintf(desc, 256, L"%d,%d: %d / %f / %f", x, y, pix & 0x00FFFFFF, (pix & 0x00FFFFFF) * (1.0f / 16777215.0f), depthScale.Apply((pix & 0x00FFFFFF) * (1.0f / 16777215.0f))); + snprintf(desc, 256, "%d,%d: %d / %f / %f", x, y, pix & 0x00FFFFFF, (pix & 0x00FFFFFF) * (1.0f / 16777215.0f), depthScale.Apply((pix & 0x00FFFFFF) * (1.0f / 16777215.0f))); break; } @@ -559,18 +569,18 @@ void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, // These are only ever going to be depth values, so let's also show scaled to 16 bit. int z24 = pix & 0x00FFFFFF; int z16 = z24 - 0x800000 + 0x8000; - _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, z16, z16 * (1.0f / 65535.0f)); + snprintf(desc, 256, "%d,%d: %d / %f", x, y, z16, z16 * (1.0f / 65535.0f)); } break; case GPU_DBG_FORMAT_24X_8BIT: - _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, (pix >> 24) & 0xFF, ((pix >> 24) & 0xFF) * (1.0f / 255.0f)); + snprintf(desc, 256, "%d,%d: %d / %f", x, y, (pix >> 24) & 0xFF, ((pix >> 24) & 0xFF) * (1.0f / 255.0f)); break; case GPU_DBG_FORMAT_FLOAT: { float pixf = *(float *)&pix; DepthScaleFactors depthScale = GetDepthScaleFactors(); - _snwprintf(desc, 256, L"%d,%d: %f / %f", x, y, pixf, depthScale.Apply(pixf)); + snprintf(desc, 256, "%d,%d: %f / %f", x, y, pixf, depthScale.Apply(pixf)); break; } @@ -585,16 +595,16 @@ void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, int z16_2 = factors.Apply(z); - _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, z16, (z - 0.5 + (1.0 / 512.0)) * 256.0); + snprintf(desc, 256, "%d,%d: %d / %f", x, y, z16, (z - 0.5 + (1.0 / 512.0)) * 256.0); } break; default: - _snwprintf(desc, 256, L"Unexpected format"); + snprintf(desc, 256, "Unexpected format"); } } -void CGEDebugger::DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, wchar_t desc[256]) { +void CGEDebugger::DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]) { u32 r = -1, g = -1, b = -1, a = -1; switch (fmt) { @@ -658,11 +668,11 @@ void CGEDebugger::DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, in break; default: - _snwprintf(desc, 256, L"Unexpected format"); + snprintf(desc, 256, "Unexpected format"); return; } - _snwprintf(desc, 256, L"%d,%d: r=%d, g=%d, b=%d, a=%d", x, y, r, g, b, a); + snprintf(desc, 256, "%d,%d: r=%d, g=%d, b=%d, a=%d", x, y, r, g, b, a); } void CGEDebugger::UpdateTextureLevel(int level) { diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index f1e23f1f75..9202c85fad 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -76,13 +76,13 @@ private: void UpdateSize(WORD width, WORD height); void SavePosition(); void UpdateTextureLevel(int level); - void DescribePrimaryPreview(const GPUgstate &state, wchar_t desc[256]); - void DescribeSecondPreview(const GPUgstate &state, wchar_t desc[256]); + void DescribePrimaryPreview(const GPUgstate &state, char desc[256]); + void DescribeSecondPreview(const GPUgstate &state, char desc[256]); void PrimaryPreviewHover(int x, int y); void SecondPreviewHover(int x, int y); void PreviewExport(const GPUDebugBuffer *buffer); - void DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, wchar_t desc[256]); - void DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, wchar_t desc[256]); + void DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]); + void DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]); u32 TexturePreviewFlags(const GPUgstate &state); diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 71e6915927..4498059207 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -318,6 +318,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/Common/TextureCacheCommon.cpp.arm \ $(SRC)/GPU/Common/TextureScalerCommon.cpp.arm \ $(SRC)/GPU/Common/ShaderCommon.cpp \ + $(SRC)/GPU/Common/ShaderWriter.cpp \ $(SRC)/GPU/Common/ShaderTranslation.cpp \ $(SRC)/GPU/Common/StencilCommon.cpp \ $(SRC)/GPU/Common/SplineCommon.cpp.arm \ diff --git a/assets/lang b/assets/lang index fd6f5bc01a..d5a2a51942 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit fd6f5bc01afb419eacca538b425c01eb2a055393 +Subproject commit d5a2a51942377820764604d9bb424fa9a879c4bd diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 3120c903c8..bd03911b48 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -236,6 +236,7 @@ SOURCES_CXX += \ $(GPUCOMMONDIR)/ShaderCommon.cpp \ $(GPUCOMMONDIR)/ShaderUniforms.cpp \ $(GPUCOMMONDIR)/ShaderTranslation.cpp \ + $(GPUCOMMONDIR)/ShaderWriter.cpp \ $(GPUCOMMONDIR)/GPUDebugInterface.cpp \ $(GPUCOMMONDIR)/DepalettizeShaderCommon.cpp \ $(GPUCOMMONDIR)/TransformCommon.cpp \