From 838a09c810f33f506132596f847cfa255e1ab089 Mon Sep 17 00:00:00 2001 From: InoriRus Date: Mon, 21 Mar 2022 19:23:27 +1000 Subject: [PATCH] add stencil support --- appveyor.yml | 2 +- source/CMakeLists.txt | 2 +- .../Emulator/Graphics/GraphicContext.h | 7 + .../Emulator/Graphics/GraphicsRender.h | 21 +- .../Emulator/Graphics/HardwareContext.h | 114 +- .../Emulator/Graphics/Objects/GpuMemory.h | 21 +- .../Emulator/Graphics/Objects/RenderTexture.h | 2 +- .../Emulator/Graphics/Objects/StorageBuffer.h | 5 + .../Graphics/Objects/StorageTexture.h | 6 +- .../Emulator/Graphics/Objects/Texture.h | 6 +- .../emulator/include/Emulator/Graphics/Pm4.h | 39 + .../include/Emulator/Graphics/Shader.h | 20 +- .../include/Emulator/Graphics/ShaderSpirv.h | 1 + .../emulator/include/Emulator/VirtualMemory.h | 3 + source/emulator/src/Graphics/Graphics.cpp | 2 + .../emulator/src/Graphics/GraphicsRender.cpp | 1046 +++++++++++------ source/emulator/src/Graphics/GraphicsRun.cpp | 148 ++- .../src/Graphics/Objects/GpuMemory.cpp | 859 +++++++++++--- .../src/Graphics/Objects/RenderTexture.cpp | 185 ++- .../src/Graphics/Objects/StorageBuffer.cpp | 21 +- .../src/Graphics/Objects/StorageTexture.cpp | 25 +- .../emulator/src/Graphics/Objects/Texture.cpp | 131 ++- source/emulator/src/Graphics/Shader.cpp | 176 ++- source/emulator/src/Graphics/ShaderSpirv.cpp | 272 ++++- source/emulator/src/Graphics/Tile.cpp | 7 + source/emulator/src/Graphics/VideoOut.cpp | 2 +- source/emulator/src/Graphics/Window.cpp | 34 +- source/emulator/src/Kernel/Memory.cpp | 4 +- source/emulator/src/RuntimeLinker.cpp | 17 +- source/emulator/src/VirtualMemory.cpp | 51 + 30 files changed, 2448 insertions(+), 781 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index df9a705..64a3336 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.0.10.build-{build} +version: 0.0.11.build-{build} image: Visual Studio 2019 environment: matrix: diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 061dda7..672a4be 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -82,7 +82,7 @@ if (KYTY_LINKER STREQUAL LD) set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000") endif() -project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.10) +project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.11) include(src_script.cmake) diff --git a/source/emulator/include/Emulator/Graphics/GraphicContext.h b/source/emulator/include/Emulator/Graphics/GraphicContext.h index 62f0ee1..7179a50 100644 --- a/source/emulator/include/Emulator/Graphics/GraphicContext.h +++ b/source/emulator/include/Emulator/Graphics/GraphicContext.h @@ -12,6 +12,8 @@ namespace Kyty::Libs::Graphics { +class CommandBuffer; + struct VulkanSwapchain { VkSwapchainKHR swapchain = nullptr; @@ -102,6 +104,11 @@ struct VulkanBuffer VkBufferUsageFlags usage = 0; }; +struct StorageVulkanBuffer: public VulkanBuffer +{ + CommandBuffer* cmd_buffer = nullptr; +}; + } // namespace Kyty::Libs::Graphics #endif // KYTY_EMU_ENABLED diff --git a/source/emulator/include/Emulator/Graphics/GraphicsRender.h b/source/emulator/include/Emulator/Graphics/GraphicsRender.h index 9e5d03e..a85581f 100644 --- a/source/emulator/include/Emulator/Graphics/GraphicsRender.h +++ b/source/emulator/include/Emulator/Graphics/GraphicsRender.h @@ -36,16 +36,16 @@ public: [[nodiscard]] bool IsInvalid() const; - void Allocate(); - void Free(); - void Begin() const; - void End() const; - void Execute(); - void ExecuteWithSemaphore(); - VulkanFramebuffer* BeginRenderPass(RenderColorInfo* color, RenderDepthInfo* depth) const; - void EndRenderPass() const; - void WaitForFence(); - void WaitForFenceAndReset(); + void Allocate(); + void Free(); + void Begin() const; + void End() const; + void Execute(); + void ExecuteWithSemaphore(); + void BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* color, RenderDepthInfo* depth) const; + void EndRenderPass() const; + void WaitForFence(); + void WaitForFenceAndReset(); [[nodiscard]] uint32_t GetIndex() const { return m_index; } VulkanCommandPool* GetPool() { return m_pool; } @@ -85,6 +85,7 @@ void GraphicsRenderDispatchDirect(CommandBuffer* buffer, HardwareContext* ctx, u uint32_t thread_group_z, uint32_t mode); void GraphicsRenderMemoryBarrier(CommandBuffer* buffer); void GraphicsRenderRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size); +void GraphicsRenderMemoryFree(uint64_t vaddr, uint64_t size); void DeleteFramebuffer(VideoOutVulkanImage* image); void DeleteFramebuffer(DepthStencilVulkanImage* image); diff --git a/source/emulator/include/Emulator/Graphics/HardwareContext.h b/source/emulator/include/Emulator/Graphics/HardwareContext.h index 65b8884..031e13a 100644 --- a/source/emulator/include/Emulator/Graphics/HardwareContext.h +++ b/source/emulator/include/Emulator/Graphics/HardwareContext.h @@ -9,24 +9,31 @@ namespace Kyty::Libs::Graphics { +struct ColorInfo +{ + bool fmask_compression_enable = false; + uint32_t fmask_compression_mode = 0; + bool cmask_fast_clear_enable = false; + bool dcc_compression_enable = false; + bool neo_mode = false; + uint32_t cmask_tile_mode = 0; + uint32_t cmask_tile_mode_neo = 0; + uint32_t format = 0; + uint32_t channel_type = 0; + uint32_t channel_order = 0; +}; + struct RenderTarget { - uint64_t base_addr = 0; - uint32_t pitch_div8_minus1 = 0; - uint32_t fmask_pitch_div8_minus1 = 0; - uint32_t slice_div64_minus1 = 0; - uint32_t base_array_slice_index = 0; - uint32_t last_array_slice_index = 0; - bool fmask_compression_enable = false; - uint32_t fmask_compression_mode = 0; - bool cmask_fast_clear_enable = false; - bool dcc_compression_enable = false; - bool neo_mode = false; - uint32_t cmask_tile_mode = 0; - uint32_t cmask_tile_mode_neo = 0; - uint32_t format = 0; - uint32_t channel_type = 0; - uint32_t channel_order = 0; + uint64_t base_addr = 0; + uint32_t pitch_div8_minus1 = 0; + uint32_t fmask_pitch_div8_minus1 = 0; + uint32_t slice_div64_minus1 = 0; + uint32_t base_array_slice_index = 0; + uint32_t last_array_slice_index = 0; + + ColorInfo color_info; + bool force_dest_alpha_to_one = false; uint32_t tile_mode = 0; uint32_t fmask_tile_mode = 0; @@ -155,6 +162,28 @@ struct DepthControl uint8_t stencilfunc_bf = 0; }; +struct StencilControl +{ + uint8_t stencil_fail = 0; + uint8_t stencil_zpass = 0; + uint8_t stencil_zfail = 0; + uint8_t stencil_fail_bf = 0; + uint8_t stencil_zpass_bf = 0; + uint8_t stencil_zfail_bf = 0; +}; + +struct StencilMask +{ + uint8_t stencil_testval = 0; + uint8_t stencil_mask = 0; + uint8_t stencil_writemask = 0; + uint8_t stencil_opval = 0; + uint8_t stencil_testval_bf = 0; + uint8_t stencil_mask_bf = 0; + uint8_t stencil_writemask_bf = 0; + uint8_t stencil_opval_bf = 0; +}; + struct ModeControl { bool cull_front = false; @@ -343,7 +372,8 @@ public: void Reset() { *this = HardwareContext(); } - void SetRenderTarget(uint32_t slot, const RenderTarget& target) { m_render_targets[slot] = target; } + void SetRenderTarget(uint32_t slot, const RenderTarget& target) { m_render_targets[slot] = target; } + void SetColorInfo(uint32_t slot, const ColorInfo& color_info) { m_render_targets[slot].color_info = color_info; } [[nodiscard]] const RenderTarget& GetRenderTargets(uint32_t slot) const { return m_render_targets[slot]; } void SetBlendControl(uint32_t slot, const BlendControl& control) { m_blend_control[slot] = control; } @@ -411,7 +441,16 @@ public: m_vs.vs_embedded = true; } - void SetPsShader(const PsStageRegisters* ps_regs) { m_ps.ps_regs = *ps_regs; } + void SetPsShader(const PsStageRegisters* ps_regs) + { + m_ps.ps_regs = *ps_regs; + m_ps.ps_embedded = false; + } + void SetPsEmbedded(uint32_t id) + { + m_ps.ps_embedded_id = id; + m_ps.ps_embedded = true; + } void SetCsShader(const CsStageRegisters* cs_regs, uint32_t shader_modifier) { @@ -419,18 +458,22 @@ public: m_cs.cs_shader_modifier = shader_modifier; } - [[nodiscard]] const BlendColor& GetBlendColor() const { return m_blend_color; } - void SetBlendColor(const BlendColor& color) { m_blend_color = color; } - [[nodiscard]] const ClipControl& GetClipControl() const { return m_clip_control; } - void SetClipControl(const ClipControl& control) { m_clip_control = control; } - [[nodiscard]] const RenderControl& GetRenderControl() const { return m_render_control; } - void SetRenderControl(const RenderControl& control) { m_render_control = control; } - [[nodiscard]] const DepthControl& GetDepthControl() const { return m_depth_control; } - void SetDepthControl(const DepthControl& control) { m_depth_control = control; } - [[nodiscard]] const ModeControl& GetModeControl() const { return m_mode_control; } - void SetModeControl(const ModeControl& control) { m_mode_control = control; } - [[nodiscard]] const EqaaControl& GetEqaaControl() const { return m_eqaa_control; } - void SetEqaaControl(const EqaaControl& control) { m_eqaa_control = control; } + [[nodiscard]] const BlendColor& GetBlendColor() const { return m_blend_color; } + void SetBlendColor(const BlendColor& color) { m_blend_color = color; } + [[nodiscard]] const ClipControl& GetClipControl() const { return m_clip_control; } + void SetClipControl(const ClipControl& control) { m_clip_control = control; } + [[nodiscard]] const RenderControl& GetRenderControl() const { return m_render_control; } + void SetRenderControl(const RenderControl& control) { m_render_control = control; } + [[nodiscard]] const DepthControl& GetDepthControl() const { return m_depth_control; } + void SetDepthControl(const DepthControl& control) { m_depth_control = control; } + [[nodiscard]] const ModeControl& GetModeControl() const { return m_mode_control; } + void SetModeControl(const ModeControl& control) { m_mode_control = control; } + [[nodiscard]] const EqaaControl& GetEqaaControl() const { return m_eqaa_control; } + void SetEqaaControl(const EqaaControl& control) { m_eqaa_control = control; } + [[nodiscard]] const StencilControl& GetStencilControl() const { return m_stencil_control; } + void SetStencilControl(const StencilControl& control) { m_stencil_control = control; } + [[nodiscard]] const StencilMask& GetStencilMask() const { return m_stencil_mask; } + void SetStencilMask(const StencilMask& mask) { m_stencil_mask = mask; } void SetVsUserSgpr(uint32_t id, uint32_t value, UserSgprType type) { @@ -460,8 +503,10 @@ public: [[nodiscard]] const VertexShaderInfo& GetVs() const { return m_vs; } [[nodiscard]] const ComputeShaderInfo& GetCs() const { return m_cs; } - [[nodiscard]] float GetDepthClearValue() const { return m_depth_clear_value; } - void SetDepthClearValue(float clear_value) { m_depth_clear_value = clear_value; } + [[nodiscard]] float GetDepthClearValue() const { return m_depth_clear_value; } + void SetDepthClearValue(float clear_value) { m_depth_clear_value = clear_value; } + [[nodiscard]] uint8_t GetStencilClearValue() const { return m_stencil_clear_value; } + void SetStencilClearValue(uint8_t clear_value) { m_stencil_clear_value = clear_value; } private: BlendControl m_blend_control[8]; @@ -479,7 +524,10 @@ private: DepthRenderTarget m_depth_render_target; RenderControl m_render_control; DepthControl m_depth_control; - float m_depth_clear_value = 0.0f; + StencilControl m_stencil_control; + StencilMask m_stencil_mask; + float m_depth_clear_value = 0.0f; + uint8_t m_stencil_clear_value = 0; ModeControl m_mode_control; EqaaControl m_eqaa_control; diff --git a/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h b/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h index 9c34868..37b9218 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h +++ b/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h @@ -10,6 +10,7 @@ namespace Kyty::Libs::Graphics { +class CommandBuffer; struct GraphicContext; struct VulkanMemory; struct VulkanBuffer; @@ -39,6 +40,12 @@ enum class GpuMemoryObjectType : uint64_t Max }; +enum class GpuMemoryScenario +{ + Common, + GenerateMips, +}; + struct GpuMemoryObject { GpuMemoryObjectType type = GpuMemoryObjectType::Invalid; @@ -50,8 +57,8 @@ class GpuObject public: using create_func_t = void* (*)(GraphicContext* ctx, const uint64_t* params, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem); - using create_from_objects_func_t = void* (*)(GraphicContext* ctx, const uint64_t* params, const Vector& objects, - VulkanMemory* mem); + using create_from_objects_func_t = void* (*)(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* params, + GpuMemoryScenario scenario, const Vector& objects, VulkanMemory* mem); using write_back_func_t = void (*)(GraphicContext* ctx, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num); using delete_func_t = void (*)(GraphicContext* ctx, void* obj, VulkanMemory* mem); using update_func_t = void (*)(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size, @@ -81,16 +88,18 @@ public: void GpuMemoryInit(); void GpuMemorySetAllocatedRange(uint64_t vaddr, uint64_t size); -void GpuMemoryFree(GraphicContext* ctx, uint64_t vaddr, uint64_t size); -void* GpuMemoryCreateObject(GraphicContext* ctx, uint64_t vaddr, uint64_t size, const GpuObject& info); -void* GpuMemoryCreateObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info); +void GpuMemoryFree(GraphicContext* ctx, uint64_t vaddr, uint64_t size, bool unmap); +void* GpuMemoryCreateObject(GraphicContext* ctx, CommandBuffer* buffer, uint64_t vaddr, uint64_t size, const GpuObject& info); +void* GpuMemoryCreateObject(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + const GpuObject& info); void GpuMemoryResetHash(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, GpuMemoryObjectType type); void GpuMemoryDbgDump(); void GpuMemoryFlush(GraphicContext* ctx); void GpuMemoryFrameDone(); void GpuMemoryWriteBack(GraphicContext* ctx); +bool GpuMemoryCheckAccessViolation(uint64_t vaddr, uint64_t size); -Vector GpuMemoryFindObjects(uint64_t vaddr, uint64_t size); +Vector GpuMemoryFindObjects(uint64_t vaddr, uint64_t size, bool exact); bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* mem); void VulkanFree(GraphicContext* ctx, VulkanMemory* mem); diff --git a/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h b/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h index 6852a6a..bd9ca27 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h +++ b/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h @@ -40,7 +40,7 @@ public: bool Equal(const uint64_t* other) const override; [[nodiscard]] create_func_t GetCreateFunc() const override; - [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override { return nullptr; }; + [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override; [[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; }; [[nodiscard]] delete_func_t GetDeleteFunc() const override; [[nodiscard]] update_func_t GetUpdateFunc() const override; diff --git a/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h index 90d2f5a..d70f20f 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h @@ -10,6 +10,9 @@ namespace Kyty::Libs::Graphics { +struct StorageVulkanBuffer; +class CommandBuffer; + class StorageBufferGpuObject: public GpuObject { public: @@ -31,6 +34,8 @@ public: [[nodiscard]] update_func_t GetUpdateFunc() const override; }; +void StorageBufferSet(CommandBuffer* cmd_buffer, StorageVulkanBuffer* buffer); + } // namespace Kyty::Libs::Graphics #endif // KYTY_EMU_ENABLED diff --git a/source/emulator/include/Emulator/Graphics/Objects/StorageTexture.h b/source/emulator/include/Emulator/Graphics/Objects/StorageTexture.h index 997af89..eafd314 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/StorageTexture.h +++ b/source/emulator/include/Emulator/Graphics/Objects/StorageTexture.h @@ -21,13 +21,13 @@ public: static constexpr int PARAM_NEO = 5; static constexpr int PARAM_SWIZZLE = 6; - StorageTextureObject(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile, - bool neo, uint32_t swizzle) + StorageTextureObject(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_level, + uint32_t levels, uint32_t tile, bool neo, uint32_t swizzle) { params[PARAM_DFMT_NFMT] = (static_cast(dfmt) << 32u) | nfmt; params[PARAM_PITCH] = pitch; params[PARAM_WIDTH_HEIGHT] = (static_cast(width) << 32u) | height; - params[PARAM_LEVELS] = levels; + params[PARAM_LEVELS] = (static_cast(base_level) << 32u) | levels; params[PARAM_TILE] = tile; params[PARAM_NEO] = neo ? 1 : 0; params[PARAM_SWIZZLE] = swizzle; diff --git a/source/emulator/include/Emulator/Graphics/Objects/Texture.h b/source/emulator/include/Emulator/Graphics/Objects/Texture.h index 989392e..7aebace 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/Texture.h +++ b/source/emulator/include/Emulator/Graphics/Objects/Texture.h @@ -21,13 +21,13 @@ public: static constexpr int PARAM_NEO = 5; static constexpr int PARAM_SWIZZLE = 6; - TextureObject(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile, bool neo, - uint32_t swizzle) + TextureObject(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_level, uint32_t levels, + uint32_t tile, bool neo, uint32_t swizzle) { params[PARAM_DFMT_NFMT] = (static_cast(dfmt) << 32u) | nfmt; params[PARAM_PITCH] = pitch; params[PARAM_WIDTH_HEIGHT] = (static_cast(width) << 32u) | height; - params[PARAM_LEVELS] = levels; + params[PARAM_LEVELS] = (static_cast(base_level) << 32u) | levels; params[PARAM_TILE] = tile; params[PARAM_NEO] = neo ? 1 : 0; params[PARAM_SWIZZLE] = swizzle; diff --git a/source/emulator/include/Emulator/Graphics/Pm4.h b/source/emulator/include/Emulator/Graphics/Pm4.h index 8f03a43..0c52e7a 100644 --- a/source/emulator/include/Emulator/Graphics/Pm4.h +++ b/source/emulator/include/Emulator/Graphics/Pm4.h @@ -111,6 +111,10 @@ constexpr uint32_t DB_HTILE_DATA_BASE = 0x5; constexpr uint32_t DB_HTILE_DATA_BASE_BASE_256B_SHIFT = 0; constexpr uint32_t DB_HTILE_DATA_BASE_BASE_256B_MASK = 0xFFFFFFFF; +constexpr uint32_t DB_STENCIL_CLEAR = 0xA; +constexpr uint32_t DB_STENCIL_CLEAR_CLEAR_SHIFT = 0; +constexpr uint32_t DB_STENCIL_CLEAR_CLEAR_MASK = 0xFF; + constexpr uint32_t DB_DEPTH_CLEAR = 0xB; constexpr uint32_t DB_DEPTH_CLEAR_DEPTH_CLEAR_SHIFT = 0; constexpr uint32_t DB_DEPTH_CLEAR_DEPTH_CLEAR_MASK = 0xFFFFFFFF; @@ -181,6 +185,40 @@ constexpr uint32_t CB_BLEND_GREEN = 0x106; constexpr uint32_t CB_BLEND_BLUE = 0x107; constexpr uint32_t CB_BLEND_ALPHA = 0x108; +constexpr uint32_t DB_STENCIL_CONTROL = 0x10B; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILFAIL_SHIFT = 0; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILFAIL_MASK = 0xF; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILZPASS_SHIFT = 4; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILZPASS_MASK = 0xF; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILZFAIL_SHIFT = 8; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILZFAIL_MASK = 0xF; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILFAIL_BF_SHIFT = 12; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILFAIL_BF_MASK = 0xF; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILZPASS_BF_SHIFT = 16; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILZPASS_BF_MASK = 0xF; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILZFAIL_BF_SHIFT = 20; +constexpr uint32_t DB_STENCIL_CONTROL_STENCILZFAIL_BF_MASK = 0xF; + +constexpr uint32_t DB_STENCILREFMASK = 0x10C; +constexpr uint32_t DB_STENCILREFMASK_STENCILTESTVAL_SHIFT = 0; +constexpr uint32_t DB_STENCILREFMASK_STENCILTESTVAL_MASK = 0xFF; +constexpr uint32_t DB_STENCILREFMASK_STENCILMASK_SHIFT = 8; +constexpr uint32_t DB_STENCILREFMASK_STENCILMASK_MASK = 0xFF; +constexpr uint32_t DB_STENCILREFMASK_STENCILWRITEMASK_SHIFT = 16; +constexpr uint32_t DB_STENCILREFMASK_STENCILWRITEMASK_MASK = 0xFF; +constexpr uint32_t DB_STENCILREFMASK_STENCILOPVAL_SHIFT = 24; +constexpr uint32_t DB_STENCILREFMASK_STENCILOPVAL_MASK = 0xFF; + +constexpr uint32_t DB_STENCILREFMASK_BF = 0x10D; +constexpr uint32_t DB_STENCILREFMASK_BF_STENCILTESTVAL_BF_SHIFT = 0; +constexpr uint32_t DB_STENCILREFMASK_BF_STENCILTESTVAL_BF_MASK = 0xFF; +constexpr uint32_t DB_STENCILREFMASK_BF_STENCILMASK_BF_SHIFT = 8; +constexpr uint32_t DB_STENCILREFMASK_BF_STENCILMASK_BF_MASK = 0xFF; +constexpr uint32_t DB_STENCILREFMASK_BF_STENCILWRITEMASK_BF_SHIFT = 16; +constexpr uint32_t DB_STENCILREFMASK_BF_STENCILWRITEMASK_BF_MASK = 0xFF; +constexpr uint32_t DB_STENCILREFMASK_BF_STENCILOPVAL_BF_SHIFT = 24; +constexpr uint32_t DB_STENCILREFMASK_BF_STENCILOPVAL_BF_MASK = 0xFF; + constexpr uint32_t PA_CL_VPORT_XSCALE = 0x10F; constexpr uint32_t SPI_PS_INPUT_CNTL_0 = 0x191; @@ -282,6 +320,7 @@ constexpr uint32_t DB_HTILE_SURFACE_DST_OUTSIDE_ZERO_TO_ONE_MASK = 0x1; constexpr uint32_t VGT_SHADER_STAGES_EN = 0x2D5; constexpr uint32_t CB_COLOR0_BASE = 0x318; +constexpr uint32_t CB_COLOR0_INFO = 0x31C; constexpr uint32_t SPI_SHADER_PGM_RSRC1_PS = 0xA; constexpr uint32_t SPI_SHADER_PGM_RSRC1_PS_VGPRS_SHIFT = 0; diff --git a/source/emulator/include/Emulator/Graphics/Shader.h b/source/emulator/include/Emulator/Graphics/Shader.h index 966c6c5..9ed2300 100644 --- a/source/emulator/include/Emulator/Graphics/Shader.h +++ b/source/emulator/include/Emulator/Graphics/Shader.h @@ -42,6 +42,7 @@ enum class ShaderInstructionType Exp, ImageLoad, ImageSample, + ImageStore, ImageStoreMip, SAddcU32, SAddI32, @@ -137,6 +138,7 @@ enum class ShaderInstructionType VCmpxGeU32, VCmpxGtU32, VCmpxNeU32, + VCmpxNeqF32, VCndmaskB32, VCosF32, VCvtF32F16, @@ -394,18 +396,24 @@ public: { return m_instructions.Contains(type, [](auto inst, auto type) { return inst.type == type; }); }); } - [[nodiscard]] bool IsEmbedded() const { return m_embedded; } - void SetEmbedded(bool embedded) { this->m_embedded = embedded; } - [[nodiscard]] uint32_t GetEmbeddedId() const { return m_embedded_id; } - void SetEmbeddedId(uint32_t embedded_id) { m_embedded_id = embedded_id; } + [[nodiscard]] bool IsVsEmbedded() const { return m_vs_embedded; } + void SetVsEmbedded(bool embedded) { this->m_vs_embedded = embedded; } + [[nodiscard]] uint32_t GetVsEmbeddedId() const { return m_vs_embedded_id; } + void SetVsEmbeddedId(uint32_t embedded_id) { m_vs_embedded_id = embedded_id; } + [[nodiscard]] bool IsPsEmbedded() const { return m_ps_embedded; } + void SetPsEmbedded(bool embedded) { this->m_ps_embedded = embedded; } + [[nodiscard]] uint32_t GetPsEmbeddedId() const { return m_ps_embedded_id; } + void SetPsEmbeddedId(uint32_t embedded_id) { m_ps_embedded_id = embedded_id; } private: Vector m_instructions; Vector m_labels; ShaderType m_type = ShaderType::Unknown; Vector m_debug_printfs; - uint32_t m_embedded_id = 0; - bool m_embedded = false; + uint32_t m_vs_embedded_id = 0; + uint32_t m_ps_embedded_id = 0; + bool m_vs_embedded = false; + bool m_ps_embedded = false; }; struct ShaderId diff --git a/source/emulator/include/Emulator/Graphics/ShaderSpirv.h b/source/emulator/include/Emulator/Graphics/ShaderSpirv.h index 7aeb6e2..84f758d 100644 --- a/source/emulator/include/Emulator/Graphics/ShaderSpirv.h +++ b/source/emulator/include/Emulator/Graphics/ShaderSpirv.h @@ -18,6 +18,7 @@ struct ShaderComputeInputInfo; String SpirvGenerateSource(const ShaderCode& code, const ShaderVertexInputInfo* vs_input_info, const ShaderPixelInputInfo* ps_input_info, const ShaderComputeInputInfo* cs_input_info); String SpirvGetEmbeddedVs(uint32_t id); +String SpirvGetEmbeddedPs(uint32_t id); } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/VirtualMemory.h b/source/emulator/include/Emulator/VirtualMemory.h index 949be0c..058bfa0 100644 --- a/source/emulator/include/Emulator/VirtualMemory.h +++ b/source/emulator/include/Emulator/VirtualMemory.h @@ -56,6 +56,7 @@ public: ExceptionType type = ExceptionType::Unknown; AccessViolationType access_violation_type = AccessViolationType::Unknown; uint64_t access_violation_vaddr = 0; + uint64_t exception_address = 0; }; using handler_func_t = void (*)(const ExceptionInfo*); @@ -70,6 +71,8 @@ public: bool Install(uint64_t base_address, uint64_t handler_addr, uint64_t image_size, handler_func_t func); bool Uninstall(); + static bool InstallVectored(handler_func_t func); + private: ExceptionHandlerPrivate* m_p = nullptr; }; diff --git a/source/emulator/src/Graphics/Graphics.cpp b/source/emulator/src/Graphics/Graphics.cpp index f3e9bc5..fc371b4 100644 --- a/source/emulator/src/Graphics/Graphics.cpp +++ b/source/emulator/src/Graphics/Graphics.cpp @@ -191,6 +191,8 @@ int KYTY_SYSV_ABI GraphicsSetPsShader350(uint32_t* cmd, uint64_t size, const uin memcpy(&cmd[1], ps_regs, 12 * 4); } + // printf("ok\n"); + return OK; } diff --git a/source/emulator/src/Graphics/GraphicsRender.cpp b/source/emulator/src/Graphics/GraphicsRender.cpp index f18828f..2086db8 100644 --- a/source/emulator/src/Graphics/GraphicsRender.cpp +++ b/source/emulator/src/Graphics/GraphicsRender.cpp @@ -46,38 +46,68 @@ struct VulkanDescriptor }; #pragma pack(push, 1) -struct PipelineParameters -{ - float viewport_scale[3] = {}; - float viewport_offset[3] = {}; - int scissor_ltrb[4] = {0}; - VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - bool with_depth = false; - bool depth_test_enable = false; - bool depth_write_enable = false; - VkCompareOp depth_compare_op = VK_COMPARE_OP_NEVER; - bool depth_bounds_test_enable = false; - float depth_min_bounds = 0.0f; - float depth_max_bounds = 0.0f; - bool stencil_test_enable = false; - uint32_t color_mask = 0; - bool cull_front = false; - bool cull_back = false; - bool face = false; - uint8_t color_srcblend = 0; - uint8_t color_comb_fcn = 0; - uint8_t color_destblend = 0; - uint8_t alpha_srcblend = 0; - uint8_t alpha_comb_fcn = 0; - uint8_t alpha_destblend = 0; - bool separate_alpha_blend = false; - bool blend_enable = false; - float blend_color_red = 0.0f; - float blend_color_green = 0.0f; - float blend_color_blue = 0.0f; - float blend_color_alpha = 0.0f; - bool operator==(const PipelineParameters& other) const; +struct PipelineStencilStaticState +{ + VkStencilOp failOp = VK_STENCIL_OP_KEEP; + VkStencilOp passOp = VK_STENCIL_OP_KEEP; + VkStencilOp depthFailOp = VK_STENCIL_OP_KEEP; + VkCompareOp compareOp = VK_COMPARE_OP_NEVER; +}; + +struct PipelineStencilDynamicState +{ + uint32_t compareMask = 0; + uint32_t writeMask = 0; + uint32_t reference = 0; +}; + +struct PipelineStaticParameters +{ + float viewport_scale[3] = {}; + float viewport_offset[3] = {}; + int scissor_ltrb[4] = {0}; + VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + bool with_depth = false; + bool depth_test_enable = false; + bool depth_write_enable = false; + VkCompareOp depth_compare_op = VK_COMPARE_OP_NEVER; + bool depth_bounds_test_enable = false; + float depth_min_bounds = 0.0f; + float depth_max_bounds = 0.0f; + bool stencil_test_enable = false; + PipelineStencilStaticState stencil_front; + PipelineStencilStaticState stencil_back; + uint32_t color_mask = 0; + bool cull_front = false; + bool cull_back = false; + bool face = false; + uint8_t color_srcblend = 0; + uint8_t color_comb_fcn = 0; + uint8_t color_destblend = 0; + uint8_t alpha_srcblend = 0; + uint8_t alpha_comb_fcn = 0; + uint8_t alpha_destblend = 0; + bool separate_alpha_blend = false; + bool blend_enable = false; + float blend_color_red = 0.0f; + float blend_color_green = 0.0f; + float blend_color_blue = 0.0f; + float blend_color_alpha = 0.0f; + + bool operator==(const PipelineStaticParameters& other) const; +}; + +struct PipelineDynamicParameters +{ + bool vk_dynamic_state_stencil_compare_mask = false; + bool vk_dynamic_state_stencil_write_mask = false; + bool vk_dynamic_state_stencil_reference = false; + + PipelineStencilDynamicState stencil_front; + PipelineStencilDynamicState stencil_back; + + bool operator==(const PipelineDynamicParameters& other) const; }; #pragma pack(pop) @@ -92,6 +122,8 @@ struct VulkanPipeline { VkPipelineLayout pipeline_layout = nullptr; VkPipeline pipeline = nullptr; + const PipelineStaticParameters* static_params = nullptr; + PipelineDynamicParameters* dynamic_params = nullptr; const PipelineAdditionalParameters* additional_params = nullptr; }; @@ -117,12 +149,13 @@ private: struct Pipeline { - uint64_t render_pass_id = 0; - ShaderId vs_shader_id; - ShaderId ps_shader_id; - ShaderId cs_shader_id; - VulkanPipeline* pipeline = nullptr; - PipelineParameters* params = nullptr; + uint64_t render_pass_id = 0; + ShaderId vs_shader_id; + ShaderId ps_shader_id; + ShaderId cs_shader_id; + VulkanPipeline* pipeline = nullptr; + PipelineStaticParameters* static_params = nullptr; + PipelineDynamicParameters* dynamic_params = nullptr; }; [[nodiscard]] VulkanPipeline* Find(const Pipeline& p) const; @@ -249,10 +282,11 @@ private: struct Framebuffer { - VulkanFramebuffer* framebuffer = nullptr; - uint64_t image_id = 0; - uint64_t depth_id = 0; - bool depth_clear_enable = false; + VulkanFramebuffer* framebuffer = nullptr; + uint64_t image_id = 0; + uint64_t depth_id = 0; + bool depth_clear_enable = false; + bool stencil_clear_enable = false; }; Core::Mutex m_mutex; @@ -324,34 +358,36 @@ private: struct RenderDepthInfo { - VkFormat format = VK_FORMAT_UNDEFINED; - uint32_t width = 0; - uint32_t height = 0; - bool htile = false; - bool neo = false; - uint64_t depth_buffer_size = 0; - uint64_t depth_buffer_vaddr = 0; - uint64_t stencil_buffer_size = 0; - uint64_t stencil_buffer_vaddr = 0; - uint64_t htile_buffer_size = 0; - uint64_t htile_buffer_vaddr = 0; - bool depth_clear_enable = false; - float depth_clear_value = 0.0f; - bool depth_test_enable = false; - bool depth_write_enable = false; - VkCompareOp depth_compare_op = VK_COMPARE_OP_NEVER; - bool depth_bounds_test_enable = false; - float depth_min_bounds = 0.0f; - float depth_max_bounds = 0.0f; - bool stencil_clear_enable = false; - uint8_t stencil_clear_value = 0; - bool stencil_test_enable = false; - VkStencilOpState stencil_front = {}; - VkStencilOpState stencil_back = {}; - DepthStencilVulkanImage* vulkan_buffer = nullptr; - uint64_t vaddr[3] = {}; - uint64_t size[3] = {}; - int vaddr_num = 0; + VkFormat format = VK_FORMAT_UNDEFINED; + uint32_t width = 0; + uint32_t height = 0; + bool htile = false; + bool neo = false; + uint64_t depth_buffer_size = 0; + uint64_t depth_buffer_vaddr = 0; + uint64_t stencil_buffer_size = 0; + uint64_t stencil_buffer_vaddr = 0; + uint64_t htile_buffer_size = 0; + uint64_t htile_buffer_vaddr = 0; + bool depth_clear_enable = false; + float depth_clear_value = 0.0f; + bool depth_test_enable = false; + bool depth_write_enable = false; + VkCompareOp depth_compare_op = VK_COMPARE_OP_NEVER; + bool depth_bounds_test_enable = false; + float depth_min_bounds = 0.0f; + float depth_max_bounds = 0.0f; + bool stencil_clear_enable = false; + uint8_t stencil_clear_value = 0; + bool stencil_test_enable = false; + PipelineStencilStaticState stencil_static_front; + PipelineStencilStaticState stencil_static_back; + PipelineStencilDynamicState stencil_dynamic_front; + PipelineStencilDynamicState stencil_dynamic_back; + DepthStencilVulkanImage* vulkan_buffer = nullptr; + uint64_t vaddr[3] = {}; + uint64_t size[3] = {}; + int vaddr_num = 0; }; enum class RenderColorType @@ -378,7 +414,8 @@ public: { if (m_pool != nullptr) { - Delete(); + // TODO(): check if destructor is called from std::_Exit() + // Delete(); } } @@ -420,42 +457,42 @@ static void rt_print(const char* func, const RenderTarget& rt) { printf("%s\n", func); - printf("\t base_addr = 0x%016" PRIx64 "\n", rt.base_addr); - printf("\t pitch_div8_minus1 = 0x%08" PRIx32 "\n", rt.pitch_div8_minus1); - printf("\t fmask_pitch_div8_minus1 = 0x%08" PRIx32 "\n", rt.fmask_pitch_div8_minus1); - printf("\t slice_div64_minus1 = 0x%08" PRIx32 "\n", rt.slice_div64_minus1); - printf("\t base_array_slice_index = 0x%08" PRIx32 "\n", rt.base_array_slice_index); - printf("\t last_array_slice_index = 0x%08" PRIx32 "\n", rt.last_array_slice_index); - printf("\t fmask_compression_enable = %s\n", rt.fmask_compression_enable ? "true" : "false"); - printf("\t fmask_compression_mode = 0x%08" PRIx32 "\n", rt.fmask_compression_mode); - printf("\t cmask_fast_clear_enable = %s\n", rt.cmask_fast_clear_enable ? "true" : "false"); - printf("\t dcc_compression_enable = %s\n", rt.dcc_compression_enable ? "true" : "false"); - printf("\t neo_mode = %s\n", rt.neo_mode ? "true" : "false"); - printf("\t cmask_tile_mode = 0x%08" PRIx32 "\n", rt.cmask_tile_mode); - printf("\t cmask_tile_mode_neo = 0x%08" PRIx32 "\n", rt.cmask_tile_mode_neo); - printf("\t format = 0x%08" PRIx32 "\n", rt.format); - printf("\t channel_type = 0x%08" PRIx32 "\n", rt.channel_type); - printf("\t channel_order = 0x%08" PRIx32 "\n", rt.channel_order); - printf("\t force_dest_alpha_to_one = %s\n", rt.force_dest_alpha_to_one ? "true" : "false"); - printf("\t tile_mode = 0x%08" PRIx32 "\n", rt.tile_mode); - printf("\t fmask_tile_mode = 0x%08" PRIx32 "\n", rt.fmask_tile_mode); - printf("\t num_samples = 0x%08" PRIx32 "\n", rt.num_samples); - printf("\t num_fragments = 0x%08" PRIx32 "\n", rt.num_fragments); - printf("\t dcc_max_uncompressed_block_size = 0x%08" PRIx32 "\n", rt.dcc_max_uncompressed_block_size); - printf("\t dcc_max_compressed_block_size = 0x%08" PRIx32 "\n", rt.dcc_max_compressed_block_size); - printf("\t dcc_min_compressed_block_size = 0x%08" PRIx32 "\n", rt.dcc_min_compressed_block_size); - printf("\t dcc_color_transform = 0x%08" PRIx32 "\n", rt.dcc_color_transform); - printf("\t dcc_enable_overwrite_combiner = %s\n", rt.dcc_enable_overwrite_combiner ? "true" : "false"); - printf("\t dcc_force_independent_blocks = %s\n", rt.dcc_force_independent_blocks ? "true" : "false"); - printf("\t cmask_addr = 0x%016" PRIx64 "\n", rt.cmask_addr); - printf("\t cmask_slice_minus1 = 0x%08" PRIx32 "\n", rt.cmask_slice_minus1); - printf("\t fmask_addr = 0x%016" PRIx64 "\n", rt.fmask_addr); - printf("\t fmask_slice_minus1 = 0x%08" PRIx32 "\n", rt.fmask_slice_minus1); - printf("\t clear_color_word0 = 0x%08" PRIx32 "\n", rt.clear_color_word0); - printf("\t clear_color_word1 = 0x%08" PRIx32 "\n", rt.clear_color_word1); - printf("\t dcc_addr = 0x%016" PRIx64 "\n", rt.dcc_addr); - printf("\t width = 0x%08" PRIx32 "\n", rt.width); - printf("\t height = 0x%08" PRIx32 "\n", rt.height); + printf("\t base_addr = 0x%016" PRIx64 "\n", rt.base_addr); + printf("\t pitch_div8_minus1 = 0x%08" PRIx32 "\n", rt.pitch_div8_minus1); + printf("\t fmask_pitch_div8_minus1 = 0x%08" PRIx32 "\n", rt.fmask_pitch_div8_minus1); + printf("\t slice_div64_minus1 = 0x%08" PRIx32 "\n", rt.slice_div64_minus1); + printf("\t base_array_slice_index = 0x%08" PRIx32 "\n", rt.base_array_slice_index); + printf("\t last_array_slice_index = 0x%08" PRIx32 "\n", rt.last_array_slice_index); + printf("\t color_info.fmask_compression_enable = %s\n", rt.color_info.fmask_compression_enable ? "true" : "false"); + printf("\t color_info.fmask_compression_mode = 0x%08" PRIx32 "\n", rt.color_info.fmask_compression_mode); + printf("\t color_info.cmask_fast_clear_enable = %s\n", rt.color_info.cmask_fast_clear_enable ? "true" : "false"); + printf("\t color_info.dcc_compression_enable = %s\n", rt.color_info.dcc_compression_enable ? "true" : "false"); + printf("\t color_info.neo_mode = %s\n", rt.color_info.neo_mode ? "true" : "false"); + printf("\t color_info.cmask_tile_mode = 0x%08" PRIx32 "\n", rt.color_info.cmask_tile_mode); + printf("\t color_info.cmask_tile_mode_neo = 0x%08" PRIx32 "\n", rt.color_info.cmask_tile_mode_neo); + printf("\t color_info.format = 0x%08" PRIx32 "\n", rt.color_info.format); + printf("\t color_info.channel_type = 0x%08" PRIx32 "\n", rt.color_info.channel_type); + printf("\t color_info.channel_order = 0x%08" PRIx32 "\n", rt.color_info.channel_order); + printf("\t force_dest_alpha_to_one = %s\n", rt.force_dest_alpha_to_one ? "true" : "false"); + printf("\t tile_mode = 0x%08" PRIx32 "\n", rt.tile_mode); + printf("\t fmask_tile_mode = 0x%08" PRIx32 "\n", rt.fmask_tile_mode); + printf("\t num_samples = 0x%08" PRIx32 "\n", rt.num_samples); + printf("\t num_fragments = 0x%08" PRIx32 "\n", rt.num_fragments); + printf("\t dcc_max_uncompressed_block_size = 0x%08" PRIx32 "\n", rt.dcc_max_uncompressed_block_size); + printf("\t dcc_max_compressed_block_size = 0x%08" PRIx32 "\n", rt.dcc_max_compressed_block_size); + printf("\t dcc_min_compressed_block_size = 0x%08" PRIx32 "\n", rt.dcc_min_compressed_block_size); + printf("\t dcc_color_transform = 0x%08" PRIx32 "\n", rt.dcc_color_transform); + printf("\t dcc_enable_overwrite_combiner = %s\n", rt.dcc_enable_overwrite_combiner ? "true" : "false"); + printf("\t dcc_force_independent_blocks = %s\n", rt.dcc_force_independent_blocks ? "true" : "false"); + printf("\t cmask_addr = 0x%016" PRIx64 "\n", rt.cmask_addr); + printf("\t cmask_slice_minus1 = 0x%08" PRIx32 "\n", rt.cmask_slice_minus1); + printf("\t fmask_addr = 0x%016" PRIx64 "\n", rt.fmask_addr); + printf("\t fmask_slice_minus1 = 0x%08" PRIx32 "\n", rt.fmask_slice_minus1); + printf("\t clear_color_word0 = 0x%08" PRIx32 "\n", rt.clear_color_word0); + printf("\t clear_color_word1 = 0x%08" PRIx32 "\n", rt.clear_color_word1); + printf("\t dcc_addr = 0x%016" PRIx64 "\n", rt.dcc_addr); + printf("\t width = 0x%08" PRIx32 "\n", rt.width); + printf("\t height = 0x%08" PRIx32 "\n", rt.height); } // NOLINTNEXTLINE(readability-function-cognitive-complexity) @@ -470,13 +507,13 @@ static void rt_check(const RenderTarget& rt) // EXIT_NOT_IMPLEMENTED(rt.slice_div64_minus1 != 0x000086ff); EXIT_NOT_IMPLEMENTED(rt.base_array_slice_index != 0x00000000); EXIT_NOT_IMPLEMENTED(rt.last_array_slice_index != 0x00000000); - EXIT_NOT_IMPLEMENTED(rt.fmask_compression_enable != false); - EXIT_NOT_IMPLEMENTED(rt.fmask_compression_mode != 0x00000000); - EXIT_NOT_IMPLEMENTED(rt.cmask_fast_clear_enable != false); - EXIT_NOT_IMPLEMENTED(rt.dcc_compression_enable != false); - EXIT_NOT_IMPLEMENTED(!render_to_texture && rt.neo_mode != Config::IsNeo()); - EXIT_NOT_IMPLEMENTED(rt.cmask_tile_mode != 0x00000000); - EXIT_NOT_IMPLEMENTED(rt.cmask_tile_mode_neo != 0x00000000); + EXIT_NOT_IMPLEMENTED(rt.color_info.fmask_compression_enable != false); + EXIT_NOT_IMPLEMENTED(rt.color_info.fmask_compression_mode != 0x00000000); + EXIT_NOT_IMPLEMENTED(rt.color_info.cmask_fast_clear_enable != false); + EXIT_NOT_IMPLEMENTED(rt.color_info.dcc_compression_enable != false); + EXIT_NOT_IMPLEMENTED(!render_to_texture && rt.color_info.neo_mode != Config::IsNeo()); + EXIT_NOT_IMPLEMENTED(rt.color_info.cmask_tile_mode != 0x00000000); + EXIT_NOT_IMPLEMENTED(rt.color_info.cmask_tile_mode_neo != 0x00000000); // EXIT_NOT_IMPLEMENTED(rt.format != 0x0000000a); // EXIT_NOT_IMPLEMENTED(rt.channel_type != 0x00000006); // EXIT_NOT_IMPLEMENTED(rt.channel_order != 0x00000001); @@ -560,7 +597,7 @@ static void z_check(const DepthRenderTarget& z) } else { EXIT_NOT_IMPLEMENTED(z.z_info.format != 0x00000003); - EXIT_NOT_IMPLEMENTED(z.z_info.tile_mode_index != (Config::IsNeo() ? 0x00000002 : 0)); + // EXIT_NOT_IMPLEMENTED(z.z_info.tile_mode_index != (Config::IsNeo() ? 0x00000002 : 0)); EXIT_NOT_IMPLEMENTED(z.z_info.num_samples != 0x00000000); // EXIT_NOT_IMPLEMENTED(z.z_info.tile_surface_enable != true); EXIT_NOT_IMPLEMENTED(z.z_info.expclear_enabled != false); @@ -579,8 +616,8 @@ static void z_check(const DepthRenderTarget& z) EXIT_NOT_IMPLEMENTED(z.stencil_info.format != 0x00000001); EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_stencil_disable != true); EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false); - EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_mode_index != (Config::IsNeo() ? 0x00000002 : 0)); - EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_split != (Config::IsNeo() ? 0x00000002 : 0)); + // EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_mode_index != (Config::IsNeo() ? 0x00000002 : 0)); + // EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_split != (Config::IsNeo() ? 0x00000002 : 0)); } if (z.z_info.format != 0 || z.stencil_info.format != 0) @@ -589,9 +626,9 @@ static void z_check(const DepthRenderTarget& z) EXIT_NOT_IMPLEMENTED(z.depth_info.array_mode != 0x00000004); EXIT_NOT_IMPLEMENTED(z.depth_info.pipe_config != (Config::IsNeo() ? 0x00000012 : 0x0c)); EXIT_NOT_IMPLEMENTED(z.depth_info.bank_width != 0x00000000); - EXIT_NOT_IMPLEMENTED(z.depth_info.bank_height != (Config::IsNeo() ? 0x00000001 : 2)); - EXIT_NOT_IMPLEMENTED(z.depth_info.macro_tile_aspect != (Config::IsNeo() ? 0x00000000 : 2)); - EXIT_NOT_IMPLEMENTED(z.depth_info.num_banks != (Config::IsNeo() ? 0x00000002 : 3)); + // EXIT_NOT_IMPLEMENTED(z.depth_info.bank_height != (Config::IsNeo() ? 0x00000001 : 2)); + // EXIT_NOT_IMPLEMENTED(z.depth_info.macro_tile_aspect != (Config::IsNeo() ? 0x00000000 : 2)); + // EXIT_NOT_IMPLEMENTED(z.depth_info.num_banks != (Config::IsNeo() ? 0x00000002 : 3)); EXIT_NOT_IMPLEMENTED(z.depth_view.slice_start != 0x00000000); EXIT_NOT_IMPLEMENTED(z.depth_view.slice_max != 0x00000000); EXIT_NOT_IMPLEMENTED(z.htile_surface.linear != 0x00000000); @@ -664,7 +701,7 @@ static void rc_print(const char* func, const RenderControl& c) static void rc_check(const RenderControl& c) { // EXIT_NOT_IMPLEMENTED(c.depth_clear_enable != false); - EXIT_NOT_IMPLEMENTED(c.stencil_clear_enable != false); + // EXIT_NOT_IMPLEMENTED(c.stencil_clear_enable != false); EXIT_NOT_IMPLEMENTED(c.resummarize_enable != false); EXIT_NOT_IMPLEMENTED(c.stencil_compress_disable != false); EXIT_NOT_IMPLEMENTED(c.depth_compress_disable != false); @@ -738,30 +775,58 @@ static void bc_check(const BlendControl& c, const BlendColor& color) EXIT_NOT_IMPLEMENTED(color.alpha != 0.0f); } -static void d_print(const char* func, const DepthControl& c) +static void d_print(const char* func, const DepthControl& c, const StencilControl& s, const StencilMask& sm) { printf("%s\n", func); - printf("\t stencil_enable = %s\n", c.stencil_enable ? "true" : "false"); - printf("\t z_enable = %s\n", c.z_enable ? "true" : "false"); - printf("\t z_write_enable = %s\n", c.z_write_enable ? "true" : "false"); - printf("\t depth_bounds_enable = %s\n", c.depth_bounds_enable ? "true" : "false"); - printf("\t zfunc = %" PRIu8 "\n", c.zfunc); - printf("\t backface_enable = %s\n", c.backface_enable ? "true" : "false"); - printf("\t stencilfunc = %" PRIu8 "\n", c.stencilfunc); - printf("\t stencilfunc_bf = %" PRIu8 "\n", c.stencilfunc_bf); + printf("\t stencil_enable = %s\n", c.stencil_enable ? "true" : "false"); + printf("\t z_enable = %s\n", c.z_enable ? "true" : "false"); + printf("\t z_write_enable = %s\n", c.z_write_enable ? "true" : "false"); + printf("\t depth_bounds_enable = %s\n", c.depth_bounds_enable ? "true" : "false"); + printf("\t zfunc = %" PRIu8 "\n", c.zfunc); + printf("\t backface_enable = %s\n", c.backface_enable ? "true" : "false"); + printf("\t stencilfunc = %" PRIu8 "\n", c.stencilfunc); + printf("\t stencilfunc_bf = %" PRIu8 "\n", c.stencilfunc_bf); + printf("\t stencil_fail = %" PRIu8 "\n", s.stencil_fail); + printf("\t stencil_zpass = %" PRIu8 "\n", s.stencil_zpass); + printf("\t stencil_zfail = %" PRIu8 "\n", s.stencil_zfail); + printf("\t stencil_fail_bf = %" PRIu8 "\n", s.stencil_fail_bf); + printf("\t stencil_zpass_bf = %" PRIu8 "\n", s.stencil_zpass_bf); + printf("\t stencil_zfail_bf = %" PRIu8 "\n", s.stencil_zfail_bf); + printf("\t stencil_testval = %" PRIu8 "\n", sm.stencil_testval); + printf("\t stencil_mask = %" PRIu8 "\n", sm.stencil_mask); + printf("\t stencil_writemask = %" PRIu8 "\n", sm.stencil_writemask); + printf("\t stencil_opval = %" PRIu8 "\n", sm.stencil_opval); + printf("\t stencil_testval_bf = %" PRIu8 "\n", sm.stencil_testval_bf); + printf("\t stencil_mask_bf = %" PRIu8 "\n", sm.stencil_mask_bf); + printf("\t stencil_writemask_bf = %" PRIu8 "\n", sm.stencil_writemask_bf); + printf("\t stencil_opval_bf = %" PRIu8 "\n", sm.stencil_opval_bf); } -static void d_check(const DepthControl& c) +static void d_check(const DepthControl& c, const StencilControl& s, const StencilMask& /*sm*/) { - EXIT_NOT_IMPLEMENTED(c.stencil_enable != false); + // EXIT_NOT_IMPLEMENTED(c.stencil_enable != false); // EXIT_NOT_IMPLEMENTED(c.z_enable != false); // EXIT_NOT_IMPLEMENTED(c.z_write_enable != false); EXIT_NOT_IMPLEMENTED(c.depth_bounds_enable != false); // EXIT_NOT_IMPLEMENTED(c.zfunc != 0); EXIT_NOT_IMPLEMENTED(c.backface_enable != false); - EXIT_NOT_IMPLEMENTED(c.stencilfunc != 0); - EXIT_NOT_IMPLEMENTED(c.stencilfunc_bf != 0); + // EXIT_NOT_IMPLEMENTED(c.stencilfunc != 0); + // EXIT_NOT_IMPLEMENTED(c.stencilfunc_bf != 0); + // EXIT_NOT_IMPLEMENTED(s.stencil_fail != 0); + // EXIT_NOT_IMPLEMENTED(s.stencil_zpass != 0); + // EXIT_NOT_IMPLEMENTED(s.stencil_zfail != 0); + EXIT_NOT_IMPLEMENTED(s.stencil_fail_bf != 0); + EXIT_NOT_IMPLEMENTED(s.stencil_zpass_bf != 0); + EXIT_NOT_IMPLEMENTED(s.stencil_zfail_bf != 0); + // EXIT_NOT_IMPLEMENTED(sm.stencil_testval != 0); + // EXIT_NOT_IMPLEMENTED(sm.stencil_mask != 0); + // EXIT_NOT_IMPLEMENTED(sm.stencil_writemask != 0); + // EXIT_NOT_IMPLEMENTED(sm.stencil_opval != 0); + // EXIT_NOT_IMPLEMENTED(sm.stencil_testval_bf != 0); + // EXIT_NOT_IMPLEMENTED(sm.stencil_mask_bf != 0); + // EXIT_NOT_IMPLEMENTED(sm.stencil_writemask_bf != 0); + // EXIT_NOT_IMPLEMENTED(sm.stencil_opval_bf != 0); } static void eqaa_print(const char* func, const EqaaControl& c) @@ -848,6 +913,8 @@ static void hw_check(const HardwareContext& hw) const auto& c = hw.GetClipControl(); const auto& rc = hw.GetRenderControl(); const auto& d = hw.GetDepthControl(); + const auto& s = hw.GetStencilControl(); + const auto& sm = hw.GetStencilMask(); const auto& mc = hw.GetModeControl(); const auto& eqaa = hw.GetEqaaControl(); @@ -856,13 +923,14 @@ static void hw_check(const HardwareContext& hw) z_check(z); clip_check(c); rc_check(rc); - d_check(d); + d_check(d, s, sm); mc_check(mc); bc_check(bc, bclr); eqaa_check(eqaa); EXIT_NOT_IMPLEMENTED(hw.GetRenderTargetMask() != 0xF && hw.GetRenderTargetMask() != 0x0); EXIT_NOT_IMPLEMENTED(hw.GetDepthClearValue() != 0.0f && hw.GetDepthClearValue() != 1.0f); + // EXIT_NOT_IMPLEMENTED(hw.GetStencilClearValue() != 0); } static void hw_print(const HardwareContext& hw) @@ -875,19 +943,22 @@ static void hw_print(const HardwareContext& hw) const auto& c = hw.GetClipControl(); const auto& rc = hw.GetRenderControl(); const auto& d = hw.GetDepthControl(); + const auto& s = hw.GetStencilControl(); + const auto& sm = hw.GetStencilMask(); const auto& mc = hw.GetModeControl(); const auto& eqaa = hw.GetEqaaControl(); printf("HardwareContext\n"); printf("\t GetRenderTargetMask() = 0x%08" PRIx32 "\n", hw.GetRenderTargetMask()); printf("\t GetDepthClearValue() = %f\n", hw.GetDepthClearValue()); + printf("\t GetStencilClearValue() = %" PRIu8 "\n", hw.GetStencilClearValue()); rt_print("RenderTraget:", rt); z_print("DepthRenderTraget:", z); vp_print("ScreenViewport:", vp); clip_print("ClipControl:", c); rc_print("RenderControl:", rc); - d_print("DepthControl:", d); + d_print("DepthStencilControlMask:", d, s, sm); mc_print("ModeControl:", mc); bc_print("BlendControl:", bc, bclr); eqaa_print("EqaaControl:", eqaa); @@ -1121,6 +1192,8 @@ void CommandPool::Delete() VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* color, RenderDepthInfo* depth) { + KYTY_PROFILER_FUNCTION(); + static std::atomic seq = 0; Core::LockGuard lock(m_mutex); @@ -1135,7 +1208,8 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* color, R for (auto& f: m_framebuffers) { if (f.framebuffer != nullptr && f.image_id == (with_color ? color->vulkan_buffer->memory.unique_id : 0) && - f.depth_id == (with_depth ? depth->vulkan_buffer->memory.unique_id : 0) && f.depth_clear_enable == depth->depth_clear_enable) + f.depth_id == (with_depth ? depth->vulkan_buffer->memory.unique_id : 0) && f.depth_clear_enable == depth->depth_clear_enable && + f.stencil_clear_enable == depth->stencil_clear_enable) { return f.framebuffer; } @@ -1174,8 +1248,8 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* color, R attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; attachments[1].loadOp = (depth->depth_clear_enable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD); attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[1].stencilLoadOp = (depth->stencil_clear_enable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD); + attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -1234,10 +1308,11 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* color, R EXIT_NOT_IMPLEMENTED(framebuffer->framebuffer == nullptr); Framebuffer fnew; - fnew.framebuffer = framebuffer; - fnew.image_id = (with_color ? color->vulkan_buffer->memory.unique_id : 0); - fnew.depth_id = (with_depth ? depth->vulkan_buffer->memory.unique_id : 0); - fnew.depth_clear_enable = depth->depth_clear_enable; + fnew.framebuffer = framebuffer; + fnew.image_id = (with_color ? color->vulkan_buffer->memory.unique_id : 0); + fnew.depth_id = (with_depth ? depth->vulkan_buffer->memory.unique_id : 0); + fnew.depth_clear_enable = depth->depth_clear_enable; + fnew.stencil_clear_enable = depth->stencil_clear_enable; bool updated = false; @@ -1611,16 +1686,20 @@ static void CreateLayout(VkDescriptorSetLayout* set_layouts, uint32_t* set_layou // NOLINTNEXTLINE(readability-function-cognitive-complexity) static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const ShaderVertexInputInfo* vs_input_info, const Vector& vs_shader, const ShaderPixelInputInfo* ps_input_info, - const Vector& ps_shader, const PipelineParameters* params, + const Vector& ps_shader, const PipelineStaticParameters* static_params, + PipelineDynamicParameters* dynamic_params, const PipelineAdditionalParameters* additional_params) { EXIT_IF(g_render_ctx == nullptr); EXIT_IF(render_pass == nullptr); - EXIT_IF(params == nullptr); + EXIT_IF(static_params == nullptr); + EXIT_IF(dynamic_params == nullptr); EXIT_IF(additional_params == nullptr); auto* pipeline = new VulkanPipeline; pipeline->additional_params = additional_params; + pipeline->static_params = static_params; + pipeline->dynamic_params = dynamic_params; auto* gctx = g_render_ctx->GetGraphicCtx(); @@ -1706,21 +1785,21 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; input_assembly.pNext = nullptr; input_assembly.flags = 0; - input_assembly.topology = params->topology; + input_assembly.topology = static_params->topology; input_assembly.primitiveRestartEnable = VK_FALSE; VkViewport viewport {}; - viewport.x = params->viewport_offset[0] - params->viewport_scale[0]; - viewport.y = params->viewport_offset[1] - params->viewport_scale[1]; - viewport.width = params->viewport_scale[0] * 2.0f; - viewport.height = params->viewport_scale[1] * 2.0f; - viewport.minDepth = params->viewport_offset[2]; - viewport.maxDepth = params->viewport_scale[2] + params->viewport_offset[2]; + viewport.x = static_params->viewport_offset[0] - static_params->viewport_scale[0]; + viewport.y = static_params->viewport_offset[1] - static_params->viewport_scale[1]; + viewport.width = static_params->viewport_scale[0] * 2.0f; + viewport.height = static_params->viewport_scale[1] * 2.0f; + viewport.minDepth = static_params->viewport_offset[2]; + viewport.maxDepth = static_params->viewport_scale[2] + static_params->viewport_offset[2]; VkRect2D scissor {}; - scissor.offset = {params->scissor_ltrb[0], params->scissor_ltrb[1]}; - scissor.extent = {static_cast(params->scissor_ltrb[2] - params->scissor_ltrb[0]), - static_cast(params->scissor_ltrb[3] - params->scissor_ltrb[1])}; + scissor.offset = {static_params->scissor_ltrb[0], static_params->scissor_ltrb[1]}; + scissor.extent = {static_cast(static_params->scissor_ltrb[2] - static_params->scissor_ltrb[0]), + static_cast(static_params->scissor_ltrb[3] - static_params->scissor_ltrb[1])}; VkPipelineViewportStateCreateInfo viewport_state {}; viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; @@ -1732,10 +1811,10 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh viewport_state.pScissors = &scissor; VkCullModeFlags cull_mode = VK_CULL_MODE_NONE; - cull_mode |= (params->cull_back ? VK_CULL_MODE_BACK_BIT : 0u); - cull_mode |= (params->cull_front ? VK_CULL_MODE_FRONT_BIT : 0u); + cull_mode |= (static_params->cull_back ? VK_CULL_MODE_BACK_BIT : 0u); + cull_mode |= (static_params->cull_front ? VK_CULL_MODE_FRONT_BIT : 0u); - VkFrontFace front_face = (params->face ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE); + VkFrontFace front_face = (static_params->face ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE); VkPipelineRasterizationDepthClipStateCreateInfoEXT clip_ext {}; clip_ext.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT; @@ -1771,31 +1850,31 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh VkColorComponentFlags color_write_mask = 0; - if (params->color_mask == 0xF) + if (static_params->color_mask == 0xF) { color_write_mask = static_cast(VK_COLOR_COMPONENT_R_BIT) | static_cast(VK_COLOR_COMPONENT_G_BIT) | static_cast(VK_COLOR_COMPONENT_B_BIT) | static_cast(VK_COLOR_COMPONENT_A_BIT); - } else if (params->color_mask == 0x0) + } else if (static_params->color_mask == 0x0) { color_write_mask = 0; } else { - EXIT("unknown mask: %u\n", params->color_mask); + EXIT("unknown mask: %u\n", static_params->color_mask); } VkPipelineColorBlendAttachmentState color_blend_attachment {}; color_blend_attachment.colorWriteMask = color_write_mask; - color_blend_attachment.blendEnable = params->blend_enable ? VK_TRUE : VK_FALSE; - color_blend_attachment.srcColorBlendFactor = get_blend_factor(params->color_srcblend); - color_blend_attachment.dstColorBlendFactor = get_blend_factor(params->color_destblend); - color_blend_attachment.colorBlendOp = get_blend_op(params->color_comb_fcn); - color_blend_attachment.srcAlphaBlendFactor = - (params->separate_alpha_blend ? get_blend_factor(params->alpha_srcblend) : color_blend_attachment.srcColorBlendFactor); - color_blend_attachment.dstAlphaBlendFactor = - (params->separate_alpha_blend ? get_blend_factor(params->alpha_destblend) : color_blend_attachment.dstColorBlendFactor); + color_blend_attachment.blendEnable = static_params->blend_enable ? VK_TRUE : VK_FALSE; + color_blend_attachment.srcColorBlendFactor = get_blend_factor(static_params->color_srcblend); + color_blend_attachment.dstColorBlendFactor = get_blend_factor(static_params->color_destblend); + color_blend_attachment.colorBlendOp = get_blend_op(static_params->color_comb_fcn); + color_blend_attachment.srcAlphaBlendFactor = (static_params->separate_alpha_blend ? get_blend_factor(static_params->alpha_srcblend) + : color_blend_attachment.srcColorBlendFactor); + color_blend_attachment.dstAlphaBlendFactor = (static_params->separate_alpha_blend ? get_blend_factor(static_params->alpha_destblend) + : color_blend_attachment.dstColorBlendFactor); color_blend_attachment.alphaBlendOp = - (params->separate_alpha_blend ? get_blend_op(params->alpha_comb_fcn) : color_blend_attachment.colorBlendOp); + (static_params->separate_alpha_blend ? get_blend_op(static_params->alpha_comb_fcn) : color_blend_attachment.colorBlendOp); VkPipelineColorBlendStateCreateInfo color_blending {}; color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; @@ -1805,10 +1884,10 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh color_blending.logicOp = VK_LOGIC_OP_COPY; color_blending.attachmentCount = 1; color_blending.pAttachments = &color_blend_attachment; - color_blending.blendConstants[0] = params->blend_color_red; - color_blending.blendConstants[1] = params->blend_color_green; - color_blending.blendConstants[2] = params->blend_color_blue; - color_blending.blendConstants[3] = params->blend_color_alpha; + color_blending.blendConstants[0] = static_params->blend_color_red; + color_blending.blendConstants[1] = static_params->blend_color_green; + color_blending.blendConstants[2] = static_params->blend_color_blue; + color_blending.blendConstants[3] = static_params->blend_color_alpha; VkDescriptorSetLayout set_layouts[2] = {}; uint32_t set_layouts_num = 0; @@ -1840,15 +1919,49 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh depth_stencil_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depth_stencil_info.pNext = nullptr; depth_stencil_info.flags = 0; - depth_stencil_info.depthTestEnable = (params->depth_test_enable ? VK_TRUE : VK_FALSE); - depth_stencil_info.depthWriteEnable = (params->depth_write_enable ? VK_TRUE : VK_FALSE); - depth_stencil_info.depthCompareOp = params->depth_compare_op; - depth_stencil_info.depthBoundsTestEnable = (params->depth_bounds_test_enable ? VK_TRUE : VK_FALSE); - depth_stencil_info.stencilTestEnable = (params->stencil_test_enable ? VK_TRUE : VK_FALSE); - depth_stencil_info.front = {}; - depth_stencil_info.back = {}; - depth_stencil_info.minDepthBounds = params->depth_min_bounds; - depth_stencil_info.maxDepthBounds = params->depth_max_bounds; + depth_stencil_info.depthTestEnable = (static_params->depth_test_enable ? VK_TRUE : VK_FALSE); + depth_stencil_info.depthWriteEnable = (static_params->depth_write_enable ? VK_TRUE : VK_FALSE); + depth_stencil_info.depthCompareOp = static_params->depth_compare_op; + depth_stencil_info.depthBoundsTestEnable = (static_params->depth_bounds_test_enable ? VK_TRUE : VK_FALSE); + depth_stencil_info.stencilTestEnable = (static_params->stencil_test_enable ? VK_TRUE : VK_FALSE); + depth_stencil_info.front.failOp = static_params->stencil_front.failOp; + depth_stencil_info.front.passOp = static_params->stencil_front.passOp; + depth_stencil_info.front.depthFailOp = static_params->stencil_front.depthFailOp; + depth_stencil_info.front.compareOp = static_params->stencil_front.compareOp; + depth_stencil_info.front.compareMask = dynamic_params->stencil_front.compareMask; + depth_stencil_info.front.writeMask = dynamic_params->stencil_front.writeMask; + depth_stencil_info.front.reference = dynamic_params->stencil_front.reference; + depth_stencil_info.back.failOp = static_params->stencil_back.failOp; + depth_stencil_info.back.passOp = static_params->stencil_back.passOp; + depth_stencil_info.back.depthFailOp = static_params->stencil_back.depthFailOp; + depth_stencil_info.back.compareOp = static_params->stencil_back.compareOp; + depth_stencil_info.back.compareMask = dynamic_params->stencil_back.compareMask; + depth_stencil_info.back.writeMask = dynamic_params->stencil_back.writeMask; + depth_stencil_info.back.reference = dynamic_params->stencil_back.reference; + depth_stencil_info.minDepthBounds = static_params->depth_min_bounds; + depth_stencil_info.maxDepthBounds = static_params->depth_max_bounds; + + VkDynamicState dynamic_states[8] = {}; + uint32_t dynamic_states_count = 0; + if (dynamic_params->vk_dynamic_state_stencil_compare_mask) + { + dynamic_states[dynamic_states_count++] = VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK; + } + if (dynamic_params->vk_dynamic_state_stencil_reference) + { + dynamic_states[dynamic_states_count++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; + } + if (dynamic_params->vk_dynamic_state_stencil_write_mask) + { + dynamic_states[dynamic_states_count++] = VK_DYNAMIC_STATE_STENCIL_WRITE_MASK; + } + + VkPipelineDynamicStateCreateInfo dynamic_state {}; + dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state.pNext = nullptr; + dynamic_state.flags = 0; + dynamic_state.dynamicStateCount = dynamic_states_count; + dynamic_state.pDynamicStates = dynamic_states; VkGraphicsPipelineCreateInfo pipeline_info {}; pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -1862,9 +1975,9 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh pipeline_info.pViewportState = &viewport_state; pipeline_info.pRasterizationState = &rasterizer; pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = (params->with_depth ? &depth_stencil_info : nullptr); + pipeline_info.pDepthStencilState = (static_params->with_depth ? &depth_stencil_info : nullptr); pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = nullptr; + pipeline_info.pDynamicState = &dynamic_state; pipeline_info.layout = pipeline->pipeline_layout; pipeline_info.renderPass = render_pass; pipeline_info.subpass = 0; @@ -1885,14 +1998,18 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh // NOLINTNEXTLINE(readability-function-cognitive-complexity) static VulkanPipeline* CreatePipelineInternal(const ShaderComputeInputInfo* input_info, const Vector& cs_shader, - const PipelineParameters* params, const PipelineAdditionalParameters* additional_params) + const PipelineStaticParameters* static_params, PipelineDynamicParameters* dynamic_params, + const PipelineAdditionalParameters* additional_params) { EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(params == nullptr); + EXIT_IF(static_params == nullptr); + EXIT_IF(dynamic_params == nullptr); EXIT_IF(additional_params == nullptr); auto* pipeline = new VulkanPipeline; pipeline->additional_params = additional_params; + pipeline->static_params = static_params; + pipeline->dynamic_params = dynamic_params; auto* gctx = g_render_ctx->GetGraphicCtx(); @@ -1970,13 +2087,19 @@ void PipelineCache::DeletePipelineInternal(Pipeline& p) EXIT_IF(p.pipeline == nullptr); EXIT_IF(p.pipeline->pipeline == nullptr); EXIT_IF(p.pipeline->pipeline_layout == nullptr); - EXIT_IF(p.params == nullptr); + EXIT_IF(p.static_params == nullptr); + EXIT_IF(p.dynamic_params == nullptr); EXIT_IF(p.pipeline->additional_params == nullptr); - delete p.params; + EXIT_IF(p.pipeline->static_params != p.static_params); + EXIT_IF(p.pipeline->dynamic_params != p.dynamic_params); + + delete p.static_params; + delete p.dynamic_params; delete p.pipeline->additional_params; - p.params = nullptr; + p.static_params = nullptr; + p.dynamic_params = nullptr; p.pipeline->additional_params = nullptr; auto* gctx = g_render_ctx->GetGraphicCtx(); @@ -1991,9 +2114,39 @@ void PipelineCache::DeletePipelineInternal(Pipeline& p) p.pipeline = nullptr; } -bool PipelineParameters::operator==(const PipelineParameters& other) const +bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other) const { - return (0 == memcmp(this, &other, sizeof(struct PipelineParameters))); + return (0 == memcmp(this, &other, sizeof(struct PipelineStaticParameters))); +} + +bool PipelineDynamicParameters::operator==(const PipelineDynamicParameters& other) const +{ + EXIT_IF(vk_dynamic_state_stencil_compare_mask != other.vk_dynamic_state_stencil_compare_mask || + vk_dynamic_state_stencil_write_mask != other.vk_dynamic_state_stencil_write_mask || + vk_dynamic_state_stencil_reference != other.vk_dynamic_state_stencil_reference); + + if (!vk_dynamic_state_stencil_compare_mask) + { + if (stencil_front.compareMask != other.stencil_front.compareMask || stencil_back.compareMask != other.stencil_back.compareMask) + { + return false; + } + } + if (!vk_dynamic_state_stencil_write_mask) + { + if (stencil_front.writeMask != other.stencil_front.writeMask || stencil_back.writeMask != other.stencil_back.writeMask) + { + return false; + } + } + if (!vk_dynamic_state_stencil_reference) + { + if (stencil_front.reference != other.stencil_front.reference || stencil_back.reference != other.stencil_back.reference) + { + return false; + } + } + return true; } VulkanPipeline* PipelineCache::Find(const Pipeline& p) const @@ -2001,7 +2154,8 @@ VulkanPipeline* PipelineCache::Find(const Pipeline& p) const for (const auto& pn: m_pipelines) { if (pn.pipeline != nullptr && p.render_pass_id == pn.render_pass_id && p.vs_shader_id == pn.vs_shader_id && - p.ps_shader_id == pn.ps_shader_id && p.cs_shader_id == pn.cs_shader_id && *p.params == *pn.params) + p.ps_shader_id == pn.ps_shader_id && p.cs_shader_id == pn.cs_shader_id && *p.static_params == *pn.static_params && + *p.dynamic_params == *pn.dynamic_params) { return pn.pipeline; } @@ -2025,8 +2179,11 @@ VulkanPipeline* PipelineCache::CreatePipeline(VulkanFramebuffer* framebuffer, Re Core::LockGuard lock(m_mutex); - ShaderDbgDumpInputInfo(vs_input_info); - ShaderDbgDumpInputInfo(ps_input_info); + if (Config::GetPrintfDirection() != Log::Direction::Silent) + { + ShaderDbgDumpInputInfo(vs_input_info); + ShaderDbgDumpInputInfo(ps_input_info); + } auto vs_id = ShaderGetIdVS(vs_regs, vs_input_info); auto ps_id = ShaderGetIdPS(ps_regs, ps_input_info); @@ -2035,50 +2192,63 @@ VulkanPipeline* PipelineCache::CreatePipeline(VulkanFramebuffer* framebuffer, Re p.render_pass_id = framebuffer->render_pass_id; p.ps_shader_id = ps_id; p.vs_shader_id = vs_id; - p.params = new PipelineParameters; + p.static_params = new PipelineStaticParameters; + p.dynamic_params = new PipelineDynamicParameters; + + p.dynamic_params->vk_dynamic_state_stencil_compare_mask = true; + p.dynamic_params->vk_dynamic_state_stencil_reference = true; + p.dynamic_params->vk_dynamic_state_stencil_write_mask = true; EXIT_NOT_IMPLEMENTED(depth->depth_test_enable && ps_input_info->ps_execute_on_noop); - p.params->viewport_scale[0] = vp.viewports[0].xscale; - p.params->viewport_scale[1] = vp.viewports[0].yscale; - p.params->viewport_scale[2] = vp.viewports[0].zscale; - p.params->viewport_offset[0] = vp.viewports[0].xoffset; - p.params->viewport_offset[1] = vp.viewports[0].yoffset; - p.params->viewport_offset[2] = vp.viewports[0].zoffset; - p.params->scissor_ltrb[0] = vp.scissor_left; - p.params->scissor_ltrb[1] = vp.scissor_top; - p.params->scissor_ltrb[2] = vp.scissor_right; - p.params->scissor_ltrb[3] = vp.scissor_bottom; - p.params->topology = topology; - p.params->with_depth = (depth->format != VK_FORMAT_UNDEFINED && depth->vulkan_buffer != nullptr); - p.params->depth_test_enable = depth->depth_test_enable; - p.params->depth_write_enable = (depth->depth_write_enable && !depth->depth_clear_enable); - p.params->depth_compare_op = depth->depth_compare_op; - p.params->depth_bounds_test_enable = depth->depth_bounds_test_enable; - p.params->depth_min_bounds = depth->depth_min_bounds; - p.params->depth_max_bounds = depth->depth_max_bounds; - p.params->stencil_test_enable = depth->stencil_test_enable; - p.params->color_mask = color_mask; - p.params->cull_back = mc.cull_back; - p.params->cull_front = mc.cull_front; - p.params->face = mc.face; - p.params->color_srcblend = bc.color_srcblend; - p.params->color_comb_fcn = bc.color_comb_fcn; - p.params->color_destblend = bc.color_destblend; - p.params->alpha_srcblend = bc.alpha_srcblend; - p.params->alpha_comb_fcn = bc.alpha_comb_fcn; - p.params->alpha_destblend = bc.alpha_destblend; - p.params->separate_alpha_blend = bc.separate_alpha_blend; - p.params->blend_enable = bc.enable; - p.params->blend_color_red = bclr.red; - p.params->blend_color_green = bclr.green; - p.params->blend_color_blue = bclr.blue; - p.params->blend_color_alpha = bclr.alpha; + p.static_params->viewport_scale[0] = vp.viewports[0].xscale; + p.static_params->viewport_scale[1] = vp.viewports[0].yscale; + p.static_params->viewport_scale[2] = vp.viewports[0].zscale; + p.static_params->viewport_offset[0] = vp.viewports[0].xoffset; + p.static_params->viewport_offset[1] = vp.viewports[0].yoffset; + p.static_params->viewport_offset[2] = vp.viewports[0].zoffset; + p.static_params->scissor_ltrb[0] = vp.scissor_left; + p.static_params->scissor_ltrb[1] = vp.scissor_top; + p.static_params->scissor_ltrb[2] = vp.scissor_right; + p.static_params->scissor_ltrb[3] = vp.scissor_bottom; + p.static_params->topology = topology; + p.static_params->with_depth = (depth->format != VK_FORMAT_UNDEFINED && depth->vulkan_buffer != nullptr); + p.static_params->depth_test_enable = depth->depth_test_enable; + p.static_params->depth_write_enable = (depth->depth_write_enable && !depth->depth_clear_enable); + p.static_params->depth_compare_op = depth->depth_compare_op; + p.static_params->depth_bounds_test_enable = depth->depth_bounds_test_enable; + p.static_params->depth_min_bounds = depth->depth_min_bounds; + p.static_params->depth_max_bounds = depth->depth_max_bounds; + p.static_params->stencil_test_enable = depth->stencil_test_enable; + p.static_params->stencil_front = depth->stencil_static_front; + p.static_params->stencil_back = depth->stencil_static_back; + p.static_params->color_mask = color_mask; + p.static_params->cull_back = mc.cull_back; + p.static_params->cull_front = mc.cull_front; + p.static_params->face = mc.face; + p.static_params->color_srcblend = bc.color_srcblend; + p.static_params->color_comb_fcn = bc.color_comb_fcn; + p.static_params->color_destblend = bc.color_destblend; + p.static_params->alpha_srcblend = bc.alpha_srcblend; + p.static_params->alpha_comb_fcn = bc.alpha_comb_fcn; + p.static_params->alpha_destblend = bc.alpha_destblend; + p.static_params->separate_alpha_blend = bc.separate_alpha_blend; + p.static_params->blend_enable = bc.enable; + p.static_params->blend_color_red = bclr.red; + p.static_params->blend_color_green = bclr.green; + p.static_params->blend_color_blue = bclr.blue; + p.static_params->blend_color_alpha = bclr.alpha; + + p.dynamic_params->stencil_front = depth->stencil_dynamic_front; + p.dynamic_params->stencil_back = depth->stencil_dynamic_back; auto* found = Find(p); if (found != nullptr) { + *found->dynamic_params = *p.dynamic_params; + delete p.static_params; + delete p.dynamic_params; return found; } @@ -2096,7 +2266,8 @@ VulkanPipeline* PipelineCache::CreatePipeline(VulkanFramebuffer* framebuffer, Re EXIT_IF(vs_shader.IsEmpty()); EXIT_IF(ps_shader.IsEmpty()); - p.pipeline = CreatePipelineInternal(framebuffer->render_pass, vs_input_info, vs_shader, ps_input_info, ps_shader, p.params, params2); + p.pipeline = CreatePipelineInternal(framebuffer->render_pass, vs_input_info, vs_shader, ps_input_info, ps_shader, p.static_params, + p.dynamic_params, params2); EXIT_NOT_IMPLEMENTED(p.pipeline == nullptr); @@ -2140,13 +2311,21 @@ VulkanPipeline* PipelineCache::CreatePipeline(const ShaderComputeInputInfo* inpu auto cs_id = ShaderGetIdCS(cs_regs, input_info); Pipeline p {}; - p.cs_shader_id = cs_id; - p.params = new PipelineParameters; + p.cs_shader_id = cs_id; + p.static_params = new PipelineStaticParameters; + p.dynamic_params = new PipelineDynamicParameters; + + p.dynamic_params->vk_dynamic_state_stencil_compare_mask = true; + p.dynamic_params->vk_dynamic_state_stencil_reference = true; + p.dynamic_params->vk_dynamic_state_stencil_write_mask = true; auto* found = Find(p); if (found != nullptr) { + *found->dynamic_params = *p.dynamic_params; + delete p.static_params; + delete p.dynamic_params; return found; } @@ -2159,7 +2338,7 @@ VulkanPipeline* PipelineCache::CreatePipeline(const ShaderComputeInputInfo* inpu auto cs_shader = ShaderRecompileCS(cs_code, input_info); EXIT_IF(cs_shader.IsEmpty()); - p.pipeline = CreatePipelineInternal(input_info, cs_shader, p.params, params2); + p.pipeline = CreatePipelineInternal(input_info, cs_shader, p.static_params, p.dynamic_params, params2); EXIT_NOT_IMPLEMENTED(p.pipeline == nullptr); @@ -2485,6 +2664,8 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, VulkanBuffer** VulkanImage** textures2d_storage, uint64_t* samplers, VulkanBuffer** gds_buffers, const ShaderBindResources& bind, const ShaderBindParameters& bind_params) { + KYTY_PROFILER_BLOCK("DescriptorCache::GetDescriptor"); + int storage_buffers_num = bind.storage_buffers.buffers_num; int textures2d_sampled_num = bind_params.textures2d_sampled_num; int textures2d_storage_num = bind_params.textures2d_storage_num; @@ -2803,7 +2984,8 @@ VkDescriptorSetLayout DescriptorCache::GetDescriptorSetLayout(Stage stage, const EXIT_IF(samplers_num < 0 || samplers_num > SAMPLERS_MAX); EXIT_IF(gds_buffers_num < 0 || gds_buffers_num > GDS_BUFFER_MAX); - EXIT_NOT_IMPLEMENTED(stage != Stage::Pixel && (textures2d_sampled_num > 0 || textures2d_storage_num > 0 || samplers_num > 0)); + EXIT_NOT_IMPLEMENTED(stage != Stage::Pixel && stage != Stage::Compute && + (textures2d_sampled_num > 0 || textures2d_storage_num > 0 || samplers_num > 0)); Core::LockGuard lock(m_mutex); Init(); @@ -2858,14 +3040,93 @@ void DeleteDescriptor(RenderTextureVulkanImage* image) g_render_ctx->GetDescriptorCache()->FreeDescriptor(image); } -static void FindRenderDepthInfo(const HardwareContext& hw, RenderDepthInfo* r) +static bool get_stencil_op(VkStencilOp* f, uint32_t* ref, uint8_t op, uint8_t testval, uint8_t opval) { + VkStencilOp vk = VK_STENCIL_OP_KEEP; + uint32_t r = opval; + bool use_ref = true; + + switch (op) + { + case 0x00: + vk = VK_STENCIL_OP_KEEP; + use_ref = false; + break; /* Keep */ + case 0x01: + vk = VK_STENCIL_OP_ZERO; + use_ref = false; + break; /* Zero */ + case 0x02: + vk = VK_STENCIL_OP_REPLACE; + r = 0xFF; + break; /* Ones */ + case 0x03: + vk = VK_STENCIL_OP_REPLACE; + r = testval; + break; /* ReplaceTest */ + case 0x04: vk = VK_STENCIL_OP_REPLACE; break; /* ReplaceOp */ + case 0x05: vk = VK_STENCIL_OP_INCREMENT_AND_CLAMP; break; /* AddClamp */ + case 0x06: vk = VK_STENCIL_OP_DECREMENT_AND_CLAMP; break; /* SubClamp */ + case 0x07: vk = VK_STENCIL_OP_INVERT; break; /* Invert */ + case 0x08: vk = VK_STENCIL_OP_INCREMENT_AND_WRAP; break; /* AddWrap */ + case 0x09: vk = VK_STENCIL_OP_DECREMENT_AND_WRAP; break; /* SubWrap */ + case 0x0a: /* And */ + case 0x0b: /* Or */ + case 0x0c: /* Xor */ + case 0x0d: /* Nand */ + case 0x0e: /* Nor */ + case 0x0f: /* Xnor */ + default: EXIT("invalid op"); + } + *f = vk; + *ref = r; + return use_ref; +} + +static void get_stencil_state(PipelineStencilStaticState* s, PipelineStencilDynamicState* d, uint8_t func, uint8_t fail, uint8_t zpass, + uint8_t zfail, uint8_t testval, uint8_t mask, uint8_t writemask, uint8_t opval) +{ + EXIT_IF(s == nullptr || d == nullptr); + + uint32_t ref[3] = {}; + bool use_ref[3] = {}; + + use_ref[0] = get_stencil_op(&s->failOp, ref + 0, fail, testval, opval); + use_ref[1] = get_stencil_op(&s->passOp, ref + 1, zpass, testval, opval); + use_ref[2] = get_stencil_op(&s->depthFailOp, ref + 2, zfail, testval, opval); + s->compareOp = static_cast(func); + d->compareMask = mask; + d->writeMask = writemask; + + if (use_ref[0]) + { + EXIT_NOT_IMPLEMENTED((ref[0] != ref[1] && use_ref[1]) || (ref[0] != ref[2] && use_ref[2])); + d->reference = ref[0]; + } else if (use_ref[1]) + { + EXIT_NOT_IMPLEMENTED(ref[1] != ref[2] && use_ref[2]); + d->reference = ref[1]; + } else if (use_ref[2]) + { + d->reference = ref[2]; + } else + { + d->reference = 0; + } +} + +static void FindRenderDepthInfo(CommandBuffer* /*buffer*/, const HardwareContext& hw, RenderDepthInfo* r) +{ + KYTY_PROFILER_FUNCTION(); + EXIT_IF(r == nullptr); bool neo = Config::IsNeo(); const auto& z = hw.GetDepthRenderTarget(); const auto& rc = hw.GetRenderControl(); const auto& dc = hw.GetDepthControl(); + const auto& sc = hw.GetStencilControl(); + const auto& sm = hw.GetStencilMask(); uint32_t size = 0; uint32_t stencil_size = 0; @@ -2928,13 +3189,31 @@ static void FindRenderDepthInfo(const HardwareContext& hw, RenderDepthInfo* r) EXIT_NOT_IMPLEMENTED(r->depth_bounds_test_enable); r->stencil_clear_enable = rc.stencil_clear_enable; - r->stencil_clear_value = 0; - EXIT_NOT_IMPLEMENTED(r->stencil_clear_enable); + r->stencil_clear_value = hw.GetStencilClearValue(); + // EXIT_NOT_IMPLEMENTED(r->stencil_clear_enable); r->stencil_test_enable = dc.stencil_enable; - // r->stencil_front = {}; - // r->stencil_back = {}; - EXIT_NOT_IMPLEMENTED(r->stencil_test_enable); + if (r->stencil_test_enable) + { + get_stencil_state(&r->stencil_static_front, &r->stencil_dynamic_front, dc.stencilfunc, sc.stencil_fail, sc.stencil_zpass, + sc.stencil_zfail, sm.stencil_testval, sm.stencil_mask, sm.stencil_writemask, sm.stencil_opval); + if (dc.backface_enable) + { + get_stencil_state(&r->stencil_static_back, &r->stencil_dynamic_back, dc.stencilfunc_bf, sc.stencil_fail_bf, sc.stencil_zpass_bf, + sc.stencil_zfail_bf, sm.stencil_testval_bf, sm.stencil_mask_bf, sm.stencil_writemask_bf, sm.stencil_opval_bf); + } else + { + r->stencil_static_back = r->stencil_static_front; + r->stencil_dynamic_back = r->stencil_dynamic_front; + } + } else + { + r->stencil_static_front = {}; + r->stencil_static_back = {}; + r->stencil_dynamic_front = {}; + r->stencil_dynamic_back = {}; + } + // EXIT_NOT_IMPLEMENTED(r->stencil_test_enable); EXIT_NOT_IMPLEMENTED(dc.backface_enable); r->vulkan_buffer = nullptr; @@ -2969,15 +3248,17 @@ static void FindRenderDepthInfo(const HardwareContext& hw, RenderDepthInfo* r) EXIT_NOT_IMPLEMENTED(r->vaddr_num == 0); r->vulkan_buffer = static_cast( - GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), r->vaddr, r->size, r->vaddr_num, vulkan_buffer_info)); + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, r->vaddr, r->size, r->vaddr_num, vulkan_buffer_info)); EXIT_NOT_IMPLEMENTED(r->vulkan_buffer == nullptr); } } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -static void FindRenderColorInfo(const HardwareContext& hw, RenderColorInfo* r) +static void FindRenderColorInfo(CommandBuffer* buffer, const HardwareContext& hw, RenderColorInfo* r) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(r == nullptr); const auto& rt = hw.GetRenderTargets(0); @@ -3018,12 +3299,12 @@ static void FindRenderColorInfo(const HardwareContext& hw, RenderColorInfo* r) if (render_to_texture) { - if (rt.format == 0xa && rt.channel_type == 0x0 && rt.channel_order == 0x0) + if (rt.color_info.format == 0xa && rt.color_info.channel_type == 0x0 && rt.color_info.channel_order == 0x0) { // Render to texture - RenderTextureObject vulkan_buffer_info(RenderTextureFormat::R8G8B8A8Unorm, width, height, tile, rt.neo_mode, pitch); + RenderTextureObject vulkan_buffer_info(RenderTextureFormat::R8G8B8A8Unorm, width, height, tile, rt.color_info.neo_mode, pitch); auto* buffer_vulkan = static_cast( - Graphics::GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), rt.base_addr, size, vulkan_buffer_info)); + Graphics::GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), buffer, rt.base_addr, size, vulkan_buffer_info)); EXIT_NOT_IMPLEMENTED(buffer_vulkan == nullptr); r->type = RenderColorType::RenderTexture; r->base_addr = rt.base_addr; @@ -3035,7 +3316,7 @@ static void FindRenderColorInfo(const HardwareContext& hw, RenderColorInfo* r) } } else { - if (rt.format == 0xa && rt.channel_type == 0x6 && rt.channel_order == 0x1) + if (rt.color_info.format == 0xa && rt.color_info.channel_type == 0x6 && rt.color_info.channel_order == 0x1) { format = 0x80000000; } else @@ -3049,7 +3330,7 @@ static void FindRenderColorInfo(const HardwareContext& hw, RenderColorInfo* r) // Offscreen buffer VideoOutBufferObject vulkan_buffer_info(format, width, height, tile, Config::IsNeo(), pitch); auto* buffer_vulkan = static_cast( - Graphics::GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), rt.base_addr, size, vulkan_buffer_info)); + Graphics::GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, rt.base_addr, size, vulkan_buffer_info)); EXIT_NOT_IMPLEMENTED(buffer_vulkan == nullptr); r->type = RenderColorType::OffscreenBuffer; r->base_addr = rt.base_addr; @@ -3094,23 +3375,30 @@ static void InvalidateMemoryObject(const RenderDepthInfo& r) } } -static RenderTextureVulkanImage* FindRenderTexture(uint64_t vaddr, uint64_t size) +static Vector FindRenderTexture(uint64_t vaddr, uint64_t size, bool exact) { - auto objects = GpuMemoryFindObjects(vaddr, size); + KYTY_PROFILER_FUNCTION(); + + Vector ret; + + auto objects = GpuMemoryFindObjects(vaddr, size, exact); for (const auto& obj: objects) { if (obj.type == GpuMemoryObjectType::RenderTexture) { - return static_cast(obj.obj); + ret.Add(static_cast(obj.obj)); } } - return nullptr; + return ret; } -static void PrepareStorageBuffers(const ShaderStorageResources& storage_buffers, VulkanBuffer** buffers, uint32_t** sgprs) +static void PrepareStorageBuffers(CommandBuffer* buffer, const ShaderStorageResources& storage_buffers, VulkanBuffer** buffers, + uint32_t** sgprs) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(buffers == nullptr); EXIT_IF(sgprs == nullptr); EXIT_IF(*sgprs == nullptr); @@ -3145,10 +3433,12 @@ static void PrepareStorageBuffers(const ShaderStorageResources& storage_buffers, StorageBufferGpuObject buf_info(stride, num_records, read_only); - auto* buf = static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, buf_info)); + auto* buf = static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, addr, size, buf_info)); EXIT_NOT_IMPLEMENTED(buf == nullptr); + StorageBufferSet(buffer, buf); + buffers[i] = buf; r.UpdateAddress(i); @@ -3165,9 +3455,11 @@ static void PrepareStorageBuffers(const ShaderStorageResources& storage_buffers, } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage** images_sampled, VulkanImage** images_storage, - uint32_t** sgprs, const bool* without_sampler) +static void PrepareTextures(CommandBuffer* buffer, const ShaderTextureResources& textures, VulkanImage** images_sampled, + VulkanImage** images_storage, uint32_t** sgprs, const bool* without_sampler) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(images_sampled == nullptr); EXIT_IF(images_storage == nullptr); EXIT_IF(sgprs == nullptr); @@ -3193,10 +3485,10 @@ static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage* // EXIT_NOT_IMPLEMENTED(r.DstSelY() != 5); // EXIT_NOT_IMPLEMENTED(r.DstSelZ() != 6); // EXIT_NOT_IMPLEMENTED(r.DstSelW() != 7); - EXIT_NOT_IMPLEMENTED(r.BaseLevel() != 0); - EXIT_NOT_IMPLEMENTED(r.LastLevel() != 0 && r.LastLevel() != 9); + // EXIT_NOT_IMPLEMENTED(r.BaseLevel() != 0); + // EXIT_NOT_IMPLEMENTED(r.LastLevel() != 0 && r.LastLevel() != 9); EXIT_NOT_IMPLEMENTED(!(r.TilingIdx() == 8 || r.TilingIdx() == 13 || r.TilingIdx() == 14)); - EXIT_NOT_IMPLEMENTED(!(r.LastLevel() == 0 && r.Pow2Pad() == false) && !(r.LastLevel() == 9 && r.Pow2Pad() == true)); + // EXIT_NOT_IMPLEMENTED(!(r.LastLevel() == 0 && r.Pow2Pad() == false) && !(r.LastLevel() == 9 && r.Pow2Pad() == true)); EXIT_NOT_IMPLEMENTED(r.Type() != 9); EXIT_NOT_IMPLEMENTED(r.Depth() != 0); // EXIT_NOT_IMPLEMENTED(r.Pitch() != 511); @@ -3212,36 +3504,41 @@ static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage* EXIT_NOT_IMPLEMENTED(read_only && !(textures.usages[i] == ShaderTextureUsage::ReadOnly)); // EXIT_NOT_IMPLEMENTED(!read_only && !(textures.usages[i] == ShaderTextureUsage::ReadWrite)); - auto addr = r.Base(); - uint32_t size = 0; - bool neo = Config::IsNeo(); - auto width = r.Width() + 1; - auto height = r.Height() + 1; - auto pitch = r.Pitch() + 1; - auto levels = r.LastLevel() - r.BaseLevel() + 1; - auto tile = r.TilingIdx(); - uint32_t swizzle = static_cast(r.DstSelX()) | (static_cast(r.DstSelY()) << 8u) | + auto addr = r.Base(); + uint32_t size = 0; + bool neo = Config::IsNeo(); + auto width = r.Width() + 1; + auto height = r.Height() + 1; + auto pitch = r.Pitch() + 1; + auto base_level = r.BaseLevel(); + auto levels = r.LastLevel() + 1; + auto tile = r.TilingIdx(); + uint32_t swizzle = static_cast(r.DstSelX()) | (static_cast(r.DstSelY()) << 8u) | (static_cast(r.DstSelZ()) << 16u) | (static_cast(r.DstSelW()) << 24u); TileGetTextureSize(r.Dfmt(), r.Nfmt(), width, height, pitch, levels, tile, neo, &size, nullptr, nullptr, nullptr); EXIT_NOT_IMPLEMENTED(size == 0); - VulkanImage* tex = FindRenderTexture(addr, size); + auto rtex = FindRenderTexture(addr, size, true); + + EXIT_NOT_IMPLEMENTED(rtex.Size() > 1); + + VulkanImage* tex = (!rtex.IsEmpty() ? rtex.At(0) : nullptr); if (tex == nullptr) { if (without_sampler[i]) { - StorageTextureObject vulkan_texture_info(r.Dfmt(), r.Nfmt(), width, height, pitch, levels, tile, neo, swizzle); + StorageTextureObject vulkan_texture_info(r.Dfmt(), r.Nfmt(), width, height, pitch, base_level, levels, tile, neo, swizzle); tex = static_cast( - GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, vulkan_texture_info)); + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), buffer, addr, size, vulkan_texture_info)); } else { - TextureObject vulkan_texture_info(r.Dfmt(), r.Nfmt(), width, height, pitch, levels, tile, neo, swizzle); + TextureObject vulkan_texture_info(r.Dfmt(), r.Nfmt(), width, height, pitch, base_level, levels, tile, neo, swizzle); - tex = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, vulkan_texture_info)); + tex = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), buffer, addr, size, vulkan_texture_info)); } } @@ -3277,6 +3574,8 @@ static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage* // NOLINTNEXTLINE(readability-function-cognitive-complexity) static void PrepareSamplers(const ShaderSamplerResources& samplers, uint64_t* sampler_ids, uint32_t** sgprs) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(sampler_ids == nullptr); EXIT_IF(sgprs == nullptr); EXIT_IF(*sgprs == nullptr); @@ -3288,7 +3587,7 @@ static void PrepareSamplers(const ShaderSamplerResources& samplers, uint64_t* sa EXIT_NOT_IMPLEMENTED(r.ClampX() != 0); EXIT_NOT_IMPLEMENTED(r.ClampY() != 0); EXIT_NOT_IMPLEMENTED(r.ClampZ() != 0); - EXIT_NOT_IMPLEMENTED(r.MaxAnisoRatio() != 0); + // EXIT_NOT_IMPLEMENTED(r.MaxAnisoRatio() != 0); EXIT_NOT_IMPLEMENTED(r.DepthCompareFunc() != 0); EXIT_NOT_IMPLEMENTED(r.ForceUnormCoords() != false); EXIT_NOT_IMPLEMENTED(r.AnisoThreshold() != 0); @@ -3326,6 +3625,8 @@ static void PrepareSamplers(const ShaderSamplerResources& samplers, uint64_t* sa static void PrepareGdsPointers(const ShaderGdsResources& gds_pointers, uint32_t** sgprs) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(sgprs == nullptr); EXIT_IF(*sgprs == nullptr); @@ -3344,10 +3645,12 @@ static void PrepareGdsPointers(const ShaderGdsResources& gds_pointers, uint32_t* } } -static void BindDescriptors(VkCommandBuffer vk_buffer, VkPipelineBindPoint pipeline_bind_point, VkPipelineLayout layout, +static void BindDescriptors(CommandBuffer* buffer, VkPipelineBindPoint pipeline_bind_point, VkPipelineLayout layout, const ShaderBindResources& bind, const ShaderBindParameters& bind_params, VkShaderStageFlags vk_stage, DescriptorCache::Stage stage) { + KYTY_PROFILER_FUNCTION(); + if (bind.push_constant_size > 0) { EXIT_NOT_IMPLEMENTED(bind.push_constant_size > DescriptorCache::PUSH_CONSTANTS_MAX * 4); @@ -3369,11 +3672,12 @@ static void BindDescriptors(VkCommandBuffer vk_buffer, VkPipelineBindPoint pipel if (bind.storage_buffers.buffers_num > 0) { - PrepareStorageBuffers(bind.storage_buffers, storage_buffers, &sgprs_ptr); + PrepareStorageBuffers(buffer, bind.storage_buffers, storage_buffers, &sgprs_ptr); } if (bind.textures2D.textures_num > 0) { - PrepareTextures(bind.textures2D, textures2d_sampled, textures2d_storage, &sgprs_ptr, bind_params.textures2d_without_sampler); + PrepareTextures(buffer, bind.textures2D, textures2d_sampled, textures2d_storage, &sgprs_ptr, + bind_params.textures2d_without_sampler); } if (bind.samplers.samplers_num > 0) { @@ -3391,11 +3695,42 @@ static void BindDescriptors(VkCommandBuffer vk_buffer, VkPipelineBindPoint pipel stage, storage_buffers, textures2d_sampled, textures2d_storage, samplers, &gds_buffer, bind, bind_params); EXIT_IF(descriptor_set == nullptr); + + auto* vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; + vkCmdBindDescriptorSets(vk_buffer, pipeline_bind_point, layout, bind.descriptor_set_slot, 1, &descriptor_set->set, 0, nullptr); vkCmdPushConstants(vk_buffer, layout, vk_stage, bind.push_constant_offset, bind.push_constant_size, sgprs); } } +static void SetDynamicParams(VkCommandBuffer vk_buffer, VulkanPipeline* pipeline) +{ + KYTY_PROFILER_FUNCTION(); + + EXIT_IF(pipeline == nullptr); + EXIT_IF(pipeline->static_params == nullptr); + EXIT_IF(pipeline->dynamic_params == nullptr); + + if (pipeline->static_params->stencil_test_enable) + { + if (pipeline->dynamic_params->vk_dynamic_state_stencil_compare_mask) + { + vkCmdSetStencilCompareMask(vk_buffer, VK_STENCIL_FACE_FRONT_BIT, pipeline->dynamic_params->stencil_front.compareMask); + vkCmdSetStencilCompareMask(vk_buffer, VK_STENCIL_FACE_BACK_BIT, pipeline->dynamic_params->stencil_back.compareMask); + } + if (pipeline->dynamic_params->vk_dynamic_state_stencil_write_mask) + { + vkCmdSetStencilWriteMask(vk_buffer, VK_STENCIL_FACE_FRONT_BIT, pipeline->dynamic_params->stencil_front.writeMask); + vkCmdSetStencilWriteMask(vk_buffer, VK_STENCIL_FACE_BACK_BIT, pipeline->dynamic_params->stencil_back.writeMask); + } + if (pipeline->dynamic_params->vk_dynamic_state_stencil_reference) + { + vkCmdSetStencilReference(vk_buffer, VK_STENCIL_FACE_FRONT_BIT, pipeline->dynamic_params->stencil_front.reference); + vkCmdSetStencilReference(vk_buffer, VK_STENCIL_FACE_BACK_BIT, pipeline->dynamic_params->stencil_back.reference); + } + } +} + void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserConfig* ucfg, uint32_t index_type_and_size, uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type) { @@ -3409,8 +3744,12 @@ void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserCo Core::LockGuard lock(g_render_ctx->GetMutex()); - if (const auto& vs = ctx->GetVs(); - ShaderIsDisabled(ctx->GetPs().ps_regs.data_addr) || (!vs.vs_embedded && ShaderIsDisabled(vs.vs_regs.GetGpuAddress()))) + if (const auto& vs = ctx->GetVs(); !vs.vs_embedded && ShaderIsDisabled(vs.vs_regs.GetGpuAddress())) + { + return; + } + + if (const auto& ps = ctx->GetPs(); !ps.ps_embedded && ShaderIsDisabled(ps.ps_regs.data_addr)) { return; } @@ -3453,12 +3792,12 @@ void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserCo EXIT_NOT_IMPLEMENTED(type != 1); RenderDepthInfo depth_info; - FindRenderDepthInfo(*ctx, &depth_info); + FindRenderDepthInfo(buffer, *ctx, &depth_info); RenderColorInfo color_info; - FindRenderColorInfo(*ctx, &color_info); + FindRenderColorInfo(buffer, *ctx, &color_info); - auto* framebuffer = buffer->BeginRenderPass(&color_info, &depth_info); + auto* framebuffer = g_render_ctx->GetFramebufferCache()->CreateFramebuffer(&color_info, &depth_info); EXIT_NOT_IMPLEMENTED(framebuffer == nullptr); EXIT_NOT_IMPLEMENTED(framebuffer->render_pass == nullptr); @@ -3480,6 +3819,8 @@ void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserCo vkCmdBindPipeline(vk_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); + SetDynamicParams(vk_buffer, pipeline); + for (int i = 0; i < vs_input_info.buffers_num; i++) { const auto& b = vs_input_info.buffers[i]; @@ -3487,26 +3828,28 @@ void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserCo uint64_t size = b.stride * b.num_records; auto* vertices = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, VertexBufferGpuObject())); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, addr, size, VertexBufferGpuObject())); VkDeviceSize offset = 0; vkCmdBindVertexBuffers(vk_buffer, i, 1, &vertices->buffer, &offset); } - BindDescriptors(vk_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline_layout, vs_input_info.bind, + BindDescriptors(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline_layout, vs_input_info.bind, pipeline->additional_params->vs_bind, VK_SHADER_STAGE_VERTEX_BIT, DescriptorCache::Stage::Vertex); - BindDescriptors(vk_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline_layout, ps_input_info.bind, + BindDescriptors(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline_layout, ps_input_info.bind, pipeline->additional_params->ps_bind, VK_SHADER_STAGE_FRAGMENT_BIT, DescriptorCache::Stage::Pixel); - VulkanBuffer* indices = static_cast( - GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(index_addr), index_size, IndexBufferGpuObject())); + VulkanBuffer* indices = static_cast(GpuMemoryCreateObject( + g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(index_addr), index_size, IndexBufferGpuObject())); EXIT_NOT_IMPLEMENTED(indices == nullptr); vkCmdBindIndexBuffer(vk_buffer, indices->buffer, 0, index_type); + buffer->BeginRenderPass(framebuffer, &color_info, &depth_info); + vkCmdDrawIndexed(vk_buffer, index_count, 1, 0, 0, 0); buffer->EndRenderPass(); @@ -3526,8 +3869,12 @@ void GraphicsRenderDrawIndexAuto(CommandBuffer* buffer, HardwareContext* ctx, Us Core::LockGuard lock(g_render_ctx->GetMutex()); - if (const auto& vs = ctx->GetVs(); - ShaderIsDisabled(ctx->GetPs().ps_regs.data_addr) || (!vs.vs_embedded && ShaderIsDisabled(vs.vs_regs.GetGpuAddress()))) + if (const auto& vs = ctx->GetVs(); !vs.vs_embedded && ShaderIsDisabled(vs.vs_regs.GetGpuAddress())) + { + return; + } + + if (const auto& ps = ctx->GetPs(); !ps.ps_embedded && ShaderIsDisabled(ps.ps_regs.data_addr)) { return; } @@ -3548,12 +3895,12 @@ void GraphicsRenderDrawIndexAuto(CommandBuffer* buffer, HardwareContext* ctx, Us EXIT_NOT_IMPLEMENTED(ctx->GetShaderStages() != 0); RenderDepthInfo depth_info; - FindRenderDepthInfo(*ctx, &depth_info); + FindRenderDepthInfo(buffer, *ctx, &depth_info); RenderColorInfo color_info; - FindRenderColorInfo(*ctx, &color_info); + FindRenderColorInfo(buffer, *ctx, &color_info); - auto* framebuffer = buffer->BeginRenderPass(&color_info, &depth_info); + auto* framebuffer = g_render_ctx->GetFramebufferCache()->CreateFramebuffer(&color_info, &depth_info); EXIT_NOT_IMPLEMENTED(framebuffer == nullptr); EXIT_NOT_IMPLEMENTED(framebuffer->render_pass == nullptr); @@ -3587,6 +3934,8 @@ void GraphicsRenderDrawIndexAuto(CommandBuffer* buffer, HardwareContext* ctx, Us vkCmdBindPipeline(vk_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); + SetDynamicParams(vk_buffer, pipeline); + for (int i = 0; i < vs_input_info.buffers_num; i++) { const auto& b = vs_input_info.buffers[i]; @@ -3594,19 +3943,21 @@ void GraphicsRenderDrawIndexAuto(CommandBuffer* buffer, HardwareContext* ctx, Us uint64_t size = b.stride * b.num_records; auto* vertices = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, VertexBufferGpuObject())); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, addr, size, VertexBufferGpuObject())); VkDeviceSize offset = 0; vkCmdBindVertexBuffers(vk_buffer, i, 1, &vertices->buffer, &offset); } - BindDescriptors(vk_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline_layout, vs_input_info.bind, + BindDescriptors(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline_layout, vs_input_info.bind, pipeline->additional_params->vs_bind, VK_SHADER_STAGE_VERTEX_BIT, DescriptorCache::Stage::Vertex); - BindDescriptors(vk_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline_layout, ps_input_info.bind, + BindDescriptors(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline_layout, ps_input_info.bind, pipeline->additional_params->ps_bind, VK_SHADER_STAGE_FRAGMENT_BIT, DescriptorCache::Stage::Pixel); + buffer->BeginRenderPass(framebuffer, &color_info, &depth_info); + switch (ucfg->GetPrimType()) { case 4: vkCmdDraw(vk_buffer, index_count, 1, 0, 0); break; @@ -3656,7 +4007,9 @@ void GraphicsRenderDispatchDirect(CommandBuffer* buffer, HardwareContext* ctx, u vkCmdBindPipeline(vk_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline); - BindDescriptors(vk_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline_layout, input_info.bind, + SetDynamicParams(vk_buffer, pipeline); + + BindDescriptors(buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline_layout, input_info.bind, pipeline->additional_params->cs_bind, VK_SHADER_STAGE_COMPUTE_BIT, DescriptorCache::Stage::Compute); vkCmdDispatch(vk_buffer, thread_group_x, thread_group_y, thread_group_z); @@ -3691,32 +4044,36 @@ void GraphicsRenderRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, u auto* vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; - VulkanImage* image = FindRenderTexture(vaddr, size); + auto images = FindRenderTexture(vaddr, size, false); - EXIT_NOT_IMPLEMENTED(image == nullptr); - EXIT_NOT_IMPLEMENTED(image->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + for (auto* image: images) + { + EXIT_NOT_IMPLEMENTED(image == nullptr); + if (image->layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { + VkImageMemoryBarrier image_memory_barrier {}; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + image_memory_barrier.oldLayout = image->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = image->image; + image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = 1; - VkImageMemoryBarrier image_memory_barrier {}; - image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_memory_barrier.pNext = nullptr; - image_memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - image_memory_barrier.oldLayout = image->layout; - image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.image = image->image; - image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_memory_barrier.subresourceRange.baseMipLevel = 0; - image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; - image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(vk_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, + &image_memory_barrier); - vkCmdPipelineBarrier(vk_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, - &image_memory_barrier); - - image->layout = image_memory_barrier.newLayout; + image->layout = image_memory_barrier.newLayout; + } + } } void GraphicsRenderWriteAtEndOfPipe(CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value) @@ -3730,8 +4087,8 @@ void GraphicsRenderWriteAtEndOfPipe(CommandBuffer* buffer, uint32_t* dst_gpu_add Graphics::LabelGpuObject label_info(value, nullptr, nullptr); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 4, label_info)); LabelSet(buffer, label); } @@ -3759,8 +4116,8 @@ void GraphicsRenderWriteAtEndOfPipeGds(CommandBuffer* buffer, uint32_t* dst_gpu_ }, nullptr, args); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 4, label_info)); LabelSet(buffer, label); } @@ -3776,8 +4133,8 @@ void GraphicsRenderWriteAtEndOfPipe(CommandBuffer* buffer, uint64_t* dst_gpu_add Graphics::LabelGpuObject label_info(value, nullptr, nullptr); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3806,8 +4163,8 @@ void GraphicsRenderWriteAtEndOfPipeClockCounter(CommandBuffer* buffer, uint64_t* }, nullptr, args); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3831,8 +4188,8 @@ void GraphicsRenderWriteAtEndOfPipeWithWriteBack(CommandBuffer* buffer, uint64_t }, nullptr); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3861,8 +4218,8 @@ void GraphicsRenderWriteAtEndOfPipeWithInterruptWriteBack(CommandBuffer* buffer, return true; }); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3884,8 +4241,8 @@ void GraphicsRenderWriteAtEndOfPipeWithInterrupt(CommandBuffer* buffer, uint64_t return true; }); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3926,8 +4283,8 @@ void GraphicsRenderWriteAtEndOfPipeWithInterruptWriteBackFlip(CommandBuffer* buf }, args); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 4, label_info)); LabelSet(buffer, label); } @@ -3959,8 +4316,8 @@ void GraphicsRenderWriteAtEndOfPipeWithFlip(CommandBuffer* buffer, uint32_t* dst }, nullptr, args); - auto* label = - static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); + auto* label = static_cast( + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), nullptr, reinterpret_cast(dst_gpu_addr), 4, label_info)); LabelSet(buffer, label); } @@ -4053,6 +4410,11 @@ void GraphicsRenderReadGds(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) g_render_ctx->GetGdsBuffer()->Read(g_render_ctx->GetGraphicCtx(), dst, dw_offset, dw_size); } +void GraphicsRenderMemoryFree(uint64_t vaddr, uint64_t size) +{ + GpuMemoryFree(g_render_ctx->GetGraphicCtx(), vaddr, size, false); +} + bool CommandBuffer::IsInvalid() const { EXIT_IF(g_render_ctx == nullptr); @@ -4222,14 +4584,12 @@ void CommandBuffer::WaitForFenceAndReset() } } -VulkanFramebuffer* CommandBuffer::BeginRenderPass(RenderColorInfo* color, RenderDepthInfo* depth) const +void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* color, RenderDepthInfo* depth) const { EXIT_IF(IsInvalid()); auto* buffer = m_pool->buffers[m_index]; - auto* framebuffer = g_render_ctx->GetFramebufferCache()->CreateFramebuffer(color, depth); - EXIT_IF(framebuffer == nullptr); bool with_depth = (depth->format != VK_FORMAT_UNDEFINED && depth->vulkan_buffer != nullptr); @@ -4239,7 +4599,7 @@ VulkanFramebuffer* CommandBuffer::BeginRenderPass(RenderColorInfo* color, Render VkClearValue clears[2]; clears[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; - clears[1].depthStencil = {depth->depth_clear_value, 0}; + clears[1].depthStencil = {depth->depth_clear_value, depth->stencil_clear_value}; VkExtent2D extent = (with_color ? color->vulkan_buffer->extent : depth->vulkan_buffer->extent); @@ -4279,8 +4639,6 @@ VulkanFramebuffer* CommandBuffer::BeginRenderPass(RenderColorInfo* color, Render } vkCmdBeginRenderPass(buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); - - return framebuffer; } void CommandBuffer::EndRenderPass() const diff --git a/source/emulator/src/Graphics/GraphicsRun.cpp b/source/emulator/src/Graphics/GraphicsRun.cpp index aacfc79..7d1e5e2 100644 --- a/source/emulator/src/Graphics/GraphicsRun.cpp +++ b/source/emulator/src/Graphics/GraphicsRun.cpp @@ -11,6 +11,7 @@ #include "Emulator/Graphics/Graphics.h" #include "Emulator/Graphics/GraphicsRender.h" #include "Emulator/Graphics/HardwareContext.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #include "Emulator/Graphics/Pm4.h" #include "Emulator/Graphics/VideoOut.h" #include "Emulator/Graphics/Window.h" @@ -610,6 +611,8 @@ void CommandProcessor::DumpConstRam(uint32_t* dst, uint32_t offset, uint32_t dw_ { Core::LockGuard lock(m_mutex); + GpuMemoryCheckAccessViolation(reinterpret_cast(dst), dw_num * 4); + memcpy(dst, m_const_ram + offset / 4, dw_num * 4); } @@ -634,6 +637,8 @@ void CommandProcessor::WriteData(uint32_t* dst, const uint32_t* src, uint32_t dw EXIT_NOT_IMPLEMENTED(write_control != 0x04100500); + GpuMemoryCheckAccessViolation(reinterpret_cast(dst), dw_num * 4); + memcpy(dst, src, dw_num * 4); } @@ -912,6 +917,11 @@ void CommandProcessor::Run(uint32_t* data, uint32_t num_dw) { KYTY_PROFILER_BLOCK("CommandProcessor::Run"); + if (num_dw > 0) + { + GraphicsRenderMemoryFree(reinterpret_cast(data), num_dw * 4); + } + auto* cmd = data; auto dw = num_dw; for (;;) @@ -1368,6 +1378,12 @@ KYTY_HW_CTX_PARSER(hw_ctx_set_ps_input) cp->GetCtx()->SetPsInputSettings(0, buffer[0]); cp->GetCtx()->SetPsInputSettings(1, buffer[1]); count = 2; + } else if (cmd_id == 0xC0036900) + { + cp->GetCtx()->SetPsInputSettings(0, buffer[0]); + cp->GetCtx()->SetPsInputSettings(1, buffer[1]); + cp->GetCtx()->SetPsInputSettings(2, buffer[2]); + count = 3; } else if (cmd_id == 0xc0046900) { cp->GetCtx()->SetPsInputSettings(0, buffer[0]); @@ -1467,6 +1483,46 @@ KYTY_HW_CTX_PARSER(hw_ctx_set_depth_control) return 1; } +KYTY_HW_CTX_PARSER(hw_ctx_set_stencil_control) +{ + EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); + EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_STENCIL_CONTROL); + + StencilControl r; + + r.stencil_fail = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILFAIL); + r.stencil_zpass = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZPASS); + r.stencil_zfail = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZFAIL); + r.stencil_fail_bf = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILFAIL_BF); + r.stencil_zpass_bf = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZPASS_BF); + r.stencil_zfail_bf = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZFAIL_BF); + + cp->GetCtx()->SetStencilControl(r); + + return 1; +} + +KYTY_HW_CTX_PARSER(hw_ctx_set_stencil_mask) +{ + EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0026900); + EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_STENCILREFMASK); + + StencilMask r; + + r.stencil_testval = KYTY_PM4_GET(buffer[0], DB_STENCILREFMASK, STENCILTESTVAL); + r.stencil_mask = KYTY_PM4_GET(buffer[0], DB_STENCILREFMASK, STENCILMASK); + r.stencil_writemask = KYTY_PM4_GET(buffer[0], DB_STENCILREFMASK, STENCILWRITEMASK); + r.stencil_opval = KYTY_PM4_GET(buffer[0], DB_STENCILREFMASK, STENCILOPVAL); + r.stencil_testval_bf = KYTY_PM4_GET(buffer[1], DB_STENCILREFMASK_BF, STENCILTESTVAL_BF); + r.stencil_mask_bf = KYTY_PM4_GET(buffer[1], DB_STENCILREFMASK_BF, STENCILMASK_BF); + r.stencil_writemask_bf = KYTY_PM4_GET(buffer[1], DB_STENCILREFMASK_BF, STENCILWRITEMASK_BF); + r.stencil_opval_bf = KYTY_PM4_GET(buffer[1], DB_STENCILREFMASK_BF, STENCILOPVAL_BF); + + cp->GetCtx()->SetStencilMask(r); + + return 2; +} + KYTY_HW_CTX_PARSER(hw_ctx_set_eqaa_control) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); @@ -1488,6 +1544,16 @@ KYTY_HW_CTX_PARSER(hw_ctx_set_eqaa_control) return 1; } +KYTY_HW_CTX_PARSER(hw_ctx_set_stencil_clear) +{ + EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); + EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_STENCIL_CLEAR); + + cp->GetCtx()->SetStencilClearValue(KYTY_PM4_GET(buffer[0], DB_STENCIL_CLEAR, CLEAR)); + + return 1; +} + KYTY_HW_CTX_PARSER(hw_ctx_set_depth_clear) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); @@ -1546,22 +1612,24 @@ KYTY_HW_CTX_PARSER(hw_ctx_set_render_target) RenderTarget r; - r.base_addr = static_cast(buffer[0]) << 8u; - r.pitch_div8_minus1 = buffer[1] & 0x7ffu; - r.fmask_pitch_div8_minus1 = (buffer[1] >> 20u) & 0x7ffu; - r.slice_div64_minus1 = buffer[2] & 0x3fffffu; - r.base_array_slice_index = buffer[3] & 0x7ffu; - r.last_array_slice_index = (buffer[3] >> 13u) & 0x7ffu; - r.fmask_compression_enable = (buffer[4] & 0x4000u) != 0; - r.fmask_compression_mode = (buffer[4] >> 26u) & 0x3u; - r.cmask_fast_clear_enable = (buffer[4] & 0x2000u) != 0; - r.dcc_compression_enable = (buffer[4] & 0x10000000u) != 0; - r.neo_mode = (buffer[4] & 0x80000000u) != 0; - r.cmask_tile_mode = (buffer[4] >> 19u) & 0x1u; - r.cmask_tile_mode_neo = (buffer[4] >> 29u) & 0x3u; - r.format = (buffer[4] >> 2u) & 0x1fu; - r.channel_type = (buffer[4] >> 8u) & 0x7u; - r.channel_order = (buffer[4] >> 11u) & 0x3u; + r.base_addr = static_cast(buffer[0]) << 8u; + r.pitch_div8_minus1 = buffer[1] & 0x7ffu; + r.fmask_pitch_div8_minus1 = (buffer[1] >> 20u) & 0x7ffu; + r.slice_div64_minus1 = buffer[2] & 0x3fffffu; + r.base_array_slice_index = buffer[3] & 0x7ffu; + r.last_array_slice_index = (buffer[3] >> 13u) & 0x7ffu; + + r.color_info.fmask_compression_enable = (buffer[4] & 0x4000u) != 0; + r.color_info.fmask_compression_mode = (buffer[4] >> 26u) & 0x3u; + r.color_info.cmask_fast_clear_enable = (buffer[4] & 0x2000u) != 0; + r.color_info.dcc_compression_enable = (buffer[4] & 0x10000000u) != 0; + r.color_info.neo_mode = (buffer[4] & 0x80000000u) != 0; + r.color_info.cmask_tile_mode = (buffer[4] >> 19u) & 0x1u; + r.color_info.cmask_tile_mode_neo = (buffer[4] >> 29u) & 0x3u; + r.color_info.format = (buffer[4] >> 2u) & 0x1fu; + r.color_info.channel_type = (buffer[4] >> 8u) & 0x7u; + r.color_info.channel_order = (buffer[4] >> 11u) & 0x3u; + r.force_dest_alpha_to_one = (buffer[5] & 0x20000u) != 0; r.tile_mode = buffer[5] & 0x1fu; r.fmask_tile_mode = (buffer[5] >> 5u) & 0x1fu; @@ -1588,6 +1656,30 @@ KYTY_HW_CTX_PARSER(hw_ctx_set_render_target) return count; } +KYTY_HW_CTX_PARSER(hw_ctx_set_color_info) +{ + EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0016900); + + uint32_t param = (cmd_offset - Pm4::CB_COLOR0_INFO) / 15; + + ColorInfo r; + + r.fmask_compression_enable = (buffer[4] & 0x4000u) != 0; + r.fmask_compression_mode = (buffer[4] >> 26u) & 0x3u; + r.cmask_fast_clear_enable = (buffer[4] & 0x2000u) != 0; + r.dcc_compression_enable = (buffer[4] & 0x10000000u) != 0; + r.neo_mode = (buffer[4] & 0x80000000u) != 0; + r.cmask_tile_mode = (buffer[4] >> 19u) & 0x1u; + r.cmask_tile_mode_neo = (buffer[4] >> 29u) & 0x3u; + r.format = (buffer[4] >> 2u) & 0x1fu; + r.channel_type = (buffer[4] >> 8u) & 0x7u; + r.channel_order = (buffer[4] >> 11u) & 0x3u; + + cp->GetCtx()->SetColorInfo(param, r); + + return 1; +} + KYTY_HW_CTX_PARSER(hw_ctx_set_render_target_mask) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); @@ -1744,6 +1836,17 @@ KYTY_HW_CTX_PARSER(hw_ctx_set_vs_embedded) return 28; } +KYTY_HW_CTX_PARSER(hw_ctx_set_ps_embedded) +{ + EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0261038); + + auto id = buffer[0]; + + cp->GetCtx()->SetPsEmbedded(id); + + return 39; +} + KYTY_HW_CTX_PARSER(hw_ctx_set_ps_shader) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0261008); @@ -2217,6 +2320,14 @@ KYTY_CP_OP_PARSER(cp_op_acquire_mem) switch (cache_action) { + case 0x02c40040: + { + EXIT_NOT_IMPLEMENTED(size_lo == 0); + EXIT_NOT_IMPLEMENTED(base_lo == 0); + cp->RenderTextureBarrier(base_lo << 8u, size_lo << 8u); + cp->WriteBack(); + } + break; case 0x02003fc0: { EXIT_NOT_IMPLEMENTED(size_lo == 0); @@ -2395,6 +2506,7 @@ KYTY_CP_OP_PARSER(cp_op_nop) case Pm4::R_PUSH_MARKER: return cp_op_push_marker(cp, cmd_id, buffer, dw, num_dw); break; case Pm4::R_POP_MARKER: return cp_op_pop_marker(cp, cmd_id, buffer, dw, num_dw); break; case Pm4::R_VS_EMBEDDED: return hw_ctx_set_vs_embedded(cp, cmd_id, 0, buffer, dw); break; + case Pm4::R_PS_EMBEDDED: return hw_ctx_set_ps_embedded(cp, cmd_id, 0, buffer, dw); break; default: break; } @@ -2411,6 +2523,7 @@ static void graphics_init_jmp_tables() } g_hw_ctx_func[Pm4::DB_RENDER_CONTROL] = hw_ctx_set_render_control; + g_hw_ctx_func[Pm4::DB_STENCIL_CLEAR] = hw_ctx_set_stencil_clear; g_hw_ctx_func[Pm4::DB_DEPTH_CLEAR] = hw_ctx_set_depth_clear; g_hw_ctx_func[0x00c] = hw_ctx_set_screen_scissor; g_hw_ctx_func[Pm4::DB_Z_INFO] = hw_ctx_set_depth_render_target; @@ -2418,6 +2531,8 @@ static void graphics_init_jmp_tables() g_hw_ctx_func[0x08d] = hw_ctx_hardware_screen_offset; g_hw_ctx_func[0x08e] = hw_ctx_set_render_target_mask; g_hw_ctx_func[Pm4::CB_BLEND_RED] = hw_ctx_set_blend_color; + g_hw_ctx_func[Pm4::DB_STENCIL_CONTROL] = hw_ctx_set_stencil_control; + g_hw_ctx_func[Pm4::DB_STENCILREFMASK] = hw_ctx_set_stencil_mask; g_hw_ctx_func[Pm4::SPI_PS_INPUT_CNTL_0] = hw_ctx_set_ps_input; g_hw_ctx_func[Pm4::DB_DEPTH_CONTROL] = hw_ctx_set_depth_control; g_hw_ctx_func[Pm4::DB_EQAA] = hw_ctx_set_eqaa_control; @@ -2430,6 +2545,7 @@ static void graphics_init_jmp_tables() for (uint32_t slot = 0; slot < 8; slot++) { g_hw_ctx_func[Pm4::CB_COLOR0_BASE + slot * 15] = hw_ctx_set_render_target; + g_hw_ctx_func[Pm4::CB_COLOR0_INFO + slot * 15] = hw_ctx_set_color_info; g_hw_ctx_func[Pm4::CB_BLEND0_CONTROL + slot * 1] = hw_ctx_set_blend_control; } diff --git a/source/emulator/src/Graphics/Objects/GpuMemory.cpp b/source/emulator/src/Graphics/Objects/GpuMemory.cpp index e039c20..91ed2df 100644 --- a/source/emulator/src/Graphics/Objects/GpuMemory.cpp +++ b/source/emulator/src/Graphics/Objects/GpuMemory.cpp @@ -9,6 +9,7 @@ #include "Emulator/Graphics/GraphicContext.h" #include "Emulator/Profiler.h" +#include "Emulator/VirtualMemory.h" #include #include @@ -21,6 +22,8 @@ namespace Kyty::Libs::Graphics { +constexpr int VADDR_BLOCKS_MAX = 3; + enum class OverlapType : uint64_t { None, @@ -38,8 +41,15 @@ constexpr uint64_t ObjectsRelation(GpuMemoryObjectType b, OverlapType relation, static_cast(b) * static_cast(OverlapType::Max) + static_cast(relation); } -OverlapType GetOverlapType(uint64_t vaddr_a, uint64_t size_a, uint64_t vaddr_b, uint64_t size_b) +static bool addr_in_block(uint64_t block_addr, uint64_t block_size, uint64_t addr) { + return addr >= block_addr && addr < block_addr + block_size; +}; + +static OverlapType GetOverlapType(uint64_t vaddr_a, uint64_t size_a, uint64_t vaddr_b, uint64_t size_b) +{ + // KYTY_PROFILER_FUNCTION(); + EXIT_IF(size_a == 0 || size_b == 0); if (vaddr_a == vaddr_b && size_a == size_b) @@ -50,8 +60,8 @@ OverlapType GetOverlapType(uint64_t vaddr_a, uint64_t size_a, uint64_t vaddr_b, uint64_t vaddr_last_a = vaddr_a + size_a - 1; uint64_t vaddr_last_b = vaddr_b + size_b - 1; - auto addr_in_block = [](uint64_t block_addr, uint64_t block_size, uint64_t addr) - { return addr >= block_addr && addr < block_addr + block_size; }; + // auto addr_in_block = [](uint64_t block_addr, uint64_t block_size, uint64_t addr) + // { return addr >= block_addr && addr < block_addr + block_size; }; bool a_b = addr_in_block(vaddr_a, size_a, vaddr_b); bool a_lb = addr_in_block(vaddr_a, size_a, vaddr_last_b); @@ -76,6 +86,54 @@ OverlapType GetOverlapType(uint64_t vaddr_a, uint64_t size_a, uint64_t vaddr_b, return OverlapType::None; } +class MemoryWatcher +{ +public: + MemoryWatcher() { EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); } + virtual ~MemoryWatcher() { KYTY_NOT_IMPLEMENTED; } + KYTY_CLASS_NO_COPY(MemoryWatcher); + + using callback_func_t = void (*)(void*, void*); + + void Watch(const uint64_t* vaddr, const uint64_t* size, int vaddr_num, callback_func_t func, void* arg0, void* arg1); + void Stop(const uint64_t* vaddr, const uint64_t* size, int vaddr_num); + bool AlreadyWatch(const uint64_t* vaddr, const uint64_t* size, int vaddr_num); + bool Check(uint64_t vaddr, uint64_t size); + + static bool Enabled() + { + static const bool enabled = !Core::dbg_is_debugger_present(); + return enabled; + } + +private: + static constexpr uint64_t PAGES_NUM = 0x400000; + + struct Callback + { + callback_func_t func = nullptr; + void* arg0 = nullptr; + void* arg1 = nullptr; + }; + + struct Block + { + bool used = false; + uint64_t vaddr[VADDR_BLOCKS_MAX] = {}; + uint64_t size[VADDR_BLOCKS_MAX] = {}; + uint64_t page_start[VADDR_BLOCKS_MAX] = {}; + uint64_t page_end[VADDR_BLOCKS_MAX] = {}; + int vaddr_num = 0; + Callback cb; + }; + + void Delete(Block* b); + + Core::Mutex m_mutex; + uint8_t m_pages[PAGES_NUM] = {}; + Vector m_blocks; +}; + class GpuMemory { public: @@ -89,13 +147,14 @@ public: bool IsAllocated(uint64_t vaddr, uint64_t size); void SetAllocatedRange(uint64_t vaddr, uint64_t size); - void Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size); + void Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size, bool unmap); - void* CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info); + void* CreateObject(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + const GpuObject& info); void ResetHash(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, GpuMemoryObjectType type); void FrameDone(); - Vector FindObjects(const uint64_t* vaddr, const uint64_t* size, int vaddr_num); + Vector FindObjects(const uint64_t* vaddr, const uint64_t* size, int vaddr_num, bool exact); // Sync: GPU -> CPU void WriteBack(GraphicContext* ctx); @@ -106,11 +165,9 @@ public: void DbgInit(); void DbgDbDump(); void DbgDbSave(const String& file_name); - void DbgDump(); private: static constexpr int OBJ_OVERLAPS_MAX = 2; - static constexpr int VADDR_BLOCKS_MAX = 3; struct AllocatedRange { @@ -123,6 +180,8 @@ private: GpuMemoryObject object; uint64_t params[GpuObject::PARAMS_MAX] = {}; uint64_t hash[VADDR_BLOCKS_MAX] = {}; + uint64_t cpu_update_time = 0; + uint64_t gpu_update_time = 0; GpuObject::write_back_func_t write_back_func = nullptr; GpuObject::delete_func_t delete_func = nullptr; GpuObject::update_func_t update_func = nullptr; @@ -152,7 +211,8 @@ private: Block block; ObjectInfo info; Vector others; - bool free = true; + GpuMemoryScenario scenario = GpuMemoryScenario::Common; + bool free = true; }; void Free(GraphicContext* ctx, int object_id); @@ -160,10 +220,17 @@ private: Vector FindBlocks(const uint64_t* vaddr, const uint64_t* size, int vaddr_num); Block CreateBlock(const uint64_t* vaddr, const uint64_t* size, int vaddr_num); void DeleteBlock(Block* b); - void Link(int id1, int id2, OverlapType rel); + void Link(int id1, int id2, OverlapType rel, GpuMemoryScenario scenario); - static void Update(GraphicContext* ctx, ObjectInfo& o, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, - const uint64_t* hash); + // Update (CPU -> GPU) + void Update(GraphicContext* ctx, int obj_id); + + static void WatchCallback(void* a0, void* a1); + + bool create_generate_mips(const Vector& others, GpuMemoryObjectType type); + bool create_all_the_same(const Vector& others); + void create_dbg_exit(const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const Vector& others, + GpuMemoryObjectType type); Core::Mutex m_mutex; @@ -216,8 +283,289 @@ private: Vector m_infos; }; -static GpuMemory* g_gpu_memory = nullptr; -static GpuResources* g_gpu_resources = nullptr; +static GpuMemory* g_gpu_memory = nullptr; +static GpuResources* g_gpu_resources = nullptr; +static MemoryWatcher* g_gpu_memory_watcher = nullptr; + +void MemoryWatcher::Watch(const uint64_t* vaddr, const uint64_t* size, int vaddr_num, callback_func_t func, void* arg0, void* arg1) +{ + KYTY_PROFILER_BLOCK("MemoryWatcher::Watch"); + + if (!Enabled()) + { + return; + } + + Core::LockGuard lock(m_mutex); + + if (AlreadyWatch(vaddr, size, vaddr_num)) + { + return; + } + + Stop(vaddr, size, vaddr_num); + + EXIT_IF(func == nullptr); + + Block nb; + nb.used = true; + nb.cb.func = func; + nb.cb.arg0 = arg0; + nb.cb.arg1 = arg1; + nb.vaddr_num = vaddr_num; + for (int i = 0; i < vaddr_num; i++) + { + EXIT_IF(size[i] == 0); + nb.vaddr[i] = vaddr[i]; + nb.size[i] = size[i]; + nb.page_start[i] = vaddr[i] >> 12u; + nb.page_end[i] = (vaddr[i] + size[i] - 1) >> 12u; + + EXIT_IF(nb.page_end[i] < nb.page_start[i]); + + struct Region + { + uint64_t start = 0; + uint64_t count = 0; + }; + + Vector rs; + + Region r; + + for (uint64_t page = nb.page_start[i]; page <= nb.page_end[i]; page++) + { + EXIT_NOT_IMPLEMENTED(page >= PAGES_NUM); + EXIT_NOT_IMPLEMENTED(m_pages[page] == 0xff); + + if (m_pages[page] == 0) + { + if (r.count == 0) + { + r.start = page; + } + r.count++; + } else + { + if (r.count > 0) + { + rs.Add(r); + r.count = 0; + } + } + + m_pages[page]++; + } + + if (r.count > 0) + { + rs.Add(r); + } + + for (const auto& r: rs) + { + Kyty::Loader::VirtualMemory::Mode old_mode = Kyty::Loader::VirtualMemory::Mode::NoAccess; + + // printf("protect %016" PRIx64 "\n", page << 12u); + + Kyty::Loader::VirtualMemory::Protect(r.start << 12u, r.count * 0x1000, Kyty::Loader::VirtualMemory::Mode::Read, &old_mode); + + EXIT_NOT_IMPLEMENTED(old_mode != Kyty::Loader::VirtualMemory::Mode::ReadWrite); + } + } + + for (auto& b: m_blocks) + { + if (!b.used) + { + b = nb; + return; + } + } + + m_blocks.Add(nb); +} + +void MemoryWatcher::Delete(Block* b) +{ + KYTY_PROFILER_BLOCK("MemoryWatcher::Delete"); + + EXIT_IF(!b->used); + + b->used = false; + + for (int i = 0; i < b->vaddr_num; i++) + { + struct Region + { + uint64_t start = 0; + uint64_t count = 0; + }; + + Vector rs; + + Region r; + + for (uint64_t page = b->page_start[i]; page <= b->page_end[i]; page++) + { + EXIT_NOT_IMPLEMENTED(m_pages[page] == 0); + + m_pages[page]--; + + if (m_pages[page] == 0) + { + if (r.count == 0) + { + r.start = page; + } + r.count++; + } else + { + if (r.count > 0) + { + rs.Add(r); + r.count = 0; + } + } + } + + if (r.count > 0) + { + rs.Add(r); + } + + for (const auto& r: rs) + { + Kyty::Loader::VirtualMemory::Mode old_mode = Kyty::Loader::VirtualMemory::Mode::NoAccess; + + // printf("unprotect %016" PRIx64 "\n", page << 12u); + + Kyty::Loader::VirtualMemory::Protect(r.start << 12u, r.count * 0x1000, Kyty::Loader::VirtualMemory::Mode::ReadWrite, &old_mode); + + EXIT_NOT_IMPLEMENTED(old_mode != Kyty::Loader::VirtualMemory::Mode::Read); + } + } +} + +void MemoryWatcher::Stop(const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + KYTY_PROFILER_BLOCK("MemoryWatcher::Stop"); + + if (!Enabled()) + { + return; + } + + Core::LockGuard lock(m_mutex); + + for (auto& b: m_blocks) + { + if (b.used && b.vaddr_num == vaddr_num) + { + bool equal = true; + for (int i = 0; i < vaddr_num; i++) + { + if (GetOverlapType(b.vaddr[i], b.size[i], vaddr[i], size[i]) != OverlapType::Equals) + { + equal = false; + break; + } + } + if (equal) + { + Delete(&b); + } + } + } +} + +bool MemoryWatcher::AlreadyWatch(const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + KYTY_PROFILER_BLOCK("MemoryWatcher::AlreadyWatch"); + + if (!Enabled()) + { + return false; + } + + Core::LockGuard lock(m_mutex); + + for (auto& b: m_blocks) + { + if (b.used && b.vaddr_num == vaddr_num) + { + bool equal = true; + for (int i = 0; i < vaddr_num; i++) + { + if (GetOverlapType(b.vaddr[i], b.size[i], vaddr[i], size[i]) != OverlapType::Equals) + { + equal = false; + break; + } + } + if (equal) + { + return true; + } + } + } + + return false; +} + +bool MemoryWatcher::Check(uint64_t vaddr, uint64_t size) +{ + if (!Enabled()) + { + return false; + } + + // printf("check begin\n"); + // + // Core::DebugStack s; + // Core::DebugStack::Trace(&s); + // s.Print(0); + + m_mutex.Lock(); + + uint64_t page_start = vaddr >> 12u; + uint64_t page_end = (vaddr + size - 1) >> 12u; + + Vector cbs; + + for (uint64_t page = page_start; page <= page_end; page++) + { + if (page < PAGES_NUM) + { + for (auto& b: m_blocks) + { + if (b.used) + { + for (int i = 0; i < b.vaddr_num; i++) + { + if (b.page_start[i] <= page && b.page_end[i] >= page) + { + cbs.Add(b.cb); + Delete(&b); + break; + } + } + } + } + } + } + + m_mutex.Unlock(); + + for (const auto& cb: cbs) + { + cb.func(cb.arg0, cb.arg1); + } + + // printf("check end\n"); + + return !cbs.IsEmpty(); +} uint32_t GpuResources::AddOwner(const String& name) { @@ -375,13 +723,20 @@ static uint64_t calc_hash(const uint8_t* buf, uint64_t size) return (size > 0 && buf != nullptr ? XXH64(buf, size, 0) : 0); } -void GpuMemory::Link(int id1, int id2, OverlapType rel) +static uint64_t get_current_time() +{ + static std::atomic_uint64_t t(0); + return ++t; +} + +void GpuMemory::Link(int id1, int id2, OverlapType rel, GpuMemoryScenario scenario) { OverlapType other_rel = OverlapType::None; switch (rel) { case OverlapType::Equals: other_rel = OverlapType::Equals; break; case OverlapType::IsContainedWithin: other_rel = OverlapType::Contains; break; + case OverlapType::Contains: other_rel = OverlapType::IsContainedWithin; break; default: EXIT("invalid rel: %s\n", Core::EnumName(rel).C_Str()); } @@ -391,60 +746,168 @@ void GpuMemory::Link(int id1, int id2, OverlapType rel) auto& h2 = m_objects[id2]; EXIT_IF(h2.free); - // EXIT_NOT_IMPLEMENTED(!h1.others.IsEmpty()); - // EXIT_NOT_IMPLEMENTED(!h2.others.IsEmpty()); - h1.others.Add({rel, id2}); h2.others.Add({other_rel, id1}); + + h1.scenario = scenario; + h2.scenario = scenario; } -void GpuMemory::Update(GraphicContext* ctx, ObjectInfo& o, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const uint64_t* hash) +void GpuMemory::Update(GraphicContext* ctx, int obj_id) { - bool need_update = false; - for (int vi = 0; vi < vaddr_num; vi++) + KYTY_PROFILER_BLOCK("GpuMemory::Update"); + + auto& h = m_objects[obj_id]; + auto& o = h.info; + bool need_update = false; + + bool mem_watch = MemoryWatcher::Enabled(); + + if ((mem_watch && o.cpu_update_time > o.gpu_update_time) || !mem_watch) { - if (o.hash[vi] != hash[vi]) + uint64_t hash[VADDR_BLOCKS_MAX] = {}; + + for (int vi = 0; vi < h.block.vaddr_num; vi++) { - printf("Update (CPU -> GPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", - Core::EnumName(o.object.type).C_Str(), vaddr[vi], size[vi]); - need_update = true; - o.hash[vi] = hash[vi]; + EXIT_IF(h.block.size[vi] == 0); + + if (o.check_hash) + { + hash[vi] = calc_hash(reinterpret_cast(h.block.vaddr[vi]), h.block.size[vi]); + } else + { + hash[vi] = 0; + } + } + + for (int vi = 0; vi < h.block.vaddr_num; vi++) + { + if (o.hash[vi] != hash[vi]) + { + printf("Update (CPU -> GPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", + Core::EnumName(o.object.type).C_Str(), h.block.vaddr[vi], h.block.size[vi]); + need_update = true; + o.hash[vi] = hash[vi]; + } } } + if (need_update) { EXIT_IF(o.update_func == nullptr); - o.update_func(ctx, o.params, o.object.obj, vaddr, size, vaddr_num); + o.update_func(ctx, o.params, o.object.obj, h.block.vaddr, h.block.size, h.block.vaddr_num); + o.gpu_update_time = get_current_time(); } + + g_gpu_memory_watcher->Watch(h.block.vaddr, h.block.size, h.block.vaddr_num, WatchCallback, this, + reinterpret_cast(static_cast(obj_id))); +} + +void GpuMemory::WatchCallback(void* a0, void* a1) +{ + auto* m = static_cast(a0); + auto index = reinterpret_cast(a1); + + m->m_mutex.Lock(); + + EXIT_NOT_IMPLEMENTED(m->m_objects[index].free); + + m->m_objects[index].info.cpu_update_time = get_current_time(); + + m->m_mutex.Unlock(); +} + +bool GpuMemory::create_generate_mips(const Vector& others, GpuMemoryObjectType type) +{ + if (others.Size() == 2 && type == GpuMemoryObjectType::RenderTexture) + { + const auto& b0 = others.At(0); + const auto& b1 = others.At(1); + OverlapType rel0 = b0.relation; + OverlapType rel1 = b1.relation; + const auto& o0 = m_objects[b0.object_id]; + const auto& o1 = m_objects[b1.object_id]; + GpuMemoryObjectType type0 = o0.info.object.type; + GpuMemoryObjectType type1 = o1.info.object.type; + + if (rel0 == OverlapType::Contains && rel1 == OverlapType::Contains && type0 == GpuMemoryObjectType::StorageBuffer && + type1 == GpuMemoryObjectType::StorageTexture && + ((o0.others.Size() == 1 && o0.scenario == GpuMemoryScenario::Common && o1.others.Size() == 1 && + o1.scenario == GpuMemoryScenario::Common) || + (o0.others.Size() >= 2 && o0.scenario == GpuMemoryScenario::GenerateMips && o1.others.Size() >= 2 && + o1.scenario == GpuMemoryScenario::GenerateMips))) + { + return true; + } + } else if (others.Size() >= 2 && type == GpuMemoryObjectType::Texture) + { + const auto& b0 = others.At(0); + const auto& b1 = others.At(1); + OverlapType rel0 = b0.relation; + OverlapType rel1 = b1.relation; + const auto& o0 = m_objects[b0.object_id]; + const auto& o1 = m_objects[b1.object_id]; + GpuMemoryObjectType type0 = o0.info.object.type; + GpuMemoryObjectType type1 = o1.info.object.type; + + if (((rel0 == OverlapType::Contains && rel1 == OverlapType::Contains) || + (rel0 == OverlapType::Equals && rel1 == OverlapType::Equals)) && + type0 == GpuMemoryObjectType::StorageBuffer && type1 == GpuMemoryObjectType::StorageTexture && + o0.scenario == GpuMemoryScenario::GenerateMips && o1.scenario == GpuMemoryScenario::GenerateMips) + { + return true; + } + } + + return false; +} + +bool GpuMemory::create_all_the_same(const Vector& others) +{ + OverlapType rel = others.At(0).relation; + GpuMemoryObjectType type = m_objects[others.At(0).object_id].info.object.type; + + return std::all_of(others.begin(), others.end(), + [rel, type, this](auto& r) { return (rel == r.relation && type == m_objects[r.object_id].info.object.type); }); +} + +void GpuMemory::create_dbg_exit(const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const Vector& others, + GpuMemoryObjectType type) +{ + printf("Exit:\n"); + + for (int vi = 0; vi < vaddr_num; vi++) + { + printf("\t vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", vaddr[vi], size[vi]); + } + + printf("\t info.type = %s\n", Core::EnumName(type).C_Str()); + for (const auto& d: others) + { + printf("\t id = %d, rel = %s\n", d.object_id, Core::EnumName(d.relation).C_Str()); + } + DbgDbDump(); + DbgDbSave(U"_gpu_memory.db"); + KYTY_NOT_IMPLEMENTED; } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info) +void* GpuMemory::CreateObject(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + const GpuObject& info) { + KYTY_PROFILER_BLOCK("GpuMemory::CreateObject", profiler::colors::Green300); + EXIT_IF(info.type == GpuMemoryObjectType::Invalid); EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num > VADDR_BLOCKS_MAX || vaddr_num <= 0); Core::LockGuard lock(m_mutex); - uint64_t hash[VADDR_BLOCKS_MAX] = {}; - - for (int vi = 0; vi < vaddr_num; vi++) - { - EXIT_IF(size[vi] == 0); - - if (info.check_hash) - { - hash[vi] = calc_hash(reinterpret_cast(vaddr[vi]), size[vi]); - } else - { - hash[vi] = 0; - } - } - bool overlap = false; bool delete_all = false; bool create_from_objects = false; + GpuMemoryScenario scenario = GpuMemoryScenario::Common; + auto others = FindBlocks(vaddr, size, vaddr_num); if (!others.IsEmpty()) @@ -456,7 +919,7 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const auto& o = h.info; if (obj.relation == OverlapType::Equals && o.object.type == info.type && info.Equal(o.params)) { - Update(ctx, o, vaddr, size, vaddr_num, hash); + Update(ctx, obj.object_id); o.use_num++; o.use_last_frame = m_current_frame; @@ -477,6 +940,7 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const switch (ObjectsRelation(o.object.type, obj.relation, info.type)) { case ObjectsRelation(GpuMemoryObjectType::StorageBuffer, OverlapType::Equals, GpuMemoryObjectType::RenderTexture): + case ObjectsRelation(GpuMemoryObjectType::StorageBuffer, OverlapType::Equals, GpuMemoryObjectType::StorageTexture): case ObjectsRelation(GpuMemoryObjectType::VideoOutBuffer, OverlapType::Equals, GpuMemoryObjectType::StorageBuffer): { overlap = true; @@ -495,30 +959,40 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const break; } default: - EXIT("unknown relation: %s - %s - %s\n", Core::EnumName(o.object.type).C_Str(), Core::EnumName(obj.relation).C_Str(), - Core::EnumName(info.type).C_Str()); + printf("unknown relation: %s - %s - %s\n", Core::EnumName(o.object.type).C_Str(), Core::EnumName(obj.relation).C_Str(), + Core::EnumName(info.type).C_Str()); + create_dbg_exit(vaddr, size, vaddr_num, others, info.type); } } else { - OverlapType rel = others.At(0).relation; - GpuMemoryObjectType type = m_objects[others.At(0).object_id].info.object.type; - for (const auto& obj: others) + if (create_generate_mips(others, info.type)) { - EXIT_NOT_IMPLEMENTED(rel != obj.relation || type != m_objects[obj.object_id].info.object.type); - } + overlap = true; + create_from_objects = true; + scenario = GpuMemoryScenario::GenerateMips; + } else + { + if (!create_all_the_same(others)) + { + create_dbg_exit(vaddr, size, vaddr_num, others, info.type); + } - switch (ObjectsRelation(type, rel, info.type)) // NOLINT - { - case ObjectsRelation(GpuMemoryObjectType::Label, OverlapType::IsContainedWithin, GpuMemoryObjectType::StorageBuffer): - delete_all = true; - break; - case ObjectsRelation(GpuMemoryObjectType::RenderTexture, OverlapType::IsContainedWithin, GpuMemoryObjectType::Texture): - overlap = true; - create_from_objects = true; - break; - default: - EXIT("unknown relation: %s - %s - %s\n", Core::EnumName(type).C_Str(), Core::EnumName(rel).C_Str(), - Core::EnumName(info.type).C_Str()); + OverlapType rel = others.At(0).relation; + GpuMemoryObjectType type = m_objects[others.At(0).object_id].info.object.type; + + switch (ObjectsRelation(type, rel, info.type)) + { + case ObjectsRelation(GpuMemoryObjectType::Label, OverlapType::IsContainedWithin, GpuMemoryObjectType::StorageBuffer): + delete_all = true; + break; + case ObjectsRelation(GpuMemoryObjectType::RenderTexture, OverlapType::IsContainedWithin, GpuMemoryObjectType::Texture): + overlap = true; + create_from_objects = true; + break; + default: + EXIT("unknown relation: %s - %s - %s\n", Core::EnumName(type).C_Str(), Core::EnumName(rel).C_Str(), + Core::EnumName(info.type).C_Str()); + } } } } @@ -545,12 +1019,29 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const o.params[i] = info.params[i]; } + uint64_t hash[VADDR_BLOCKS_MAX] = {}; + + for (int vi = 0; vi < vaddr_num; vi++) + { + EXIT_IF(size[vi] == 0); + + if (info.check_hash) + { + hash[vi] = calc_hash(reinterpret_cast(vaddr[vi]), size[vi]); + } else + { + hash[vi] = 0; + } + } + o.object.type = info.type; o.object.obj = nullptr; for (int vi = 0; vi < vaddr_num; vi++) { o.hash[vi] = hash[vi]; } + o.cpu_update_time = get_current_time(); + o.gpu_update_time = o.cpu_update_time; if (create_from_objects) { @@ -562,7 +1053,7 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const } auto create_func = info.GetCreateFromObjectsFunc(); EXIT_IF(create_func == nullptr); - o.object.obj = create_func(ctx, o.params, objects, &o.mem); + o.object.obj = create_func(ctx, buffer, o.params, scenario, objects, &o.mem); } else { o.object.obj = info.GetCreateFunc()(ctx, o.params, vaddr, size, vaddr_num, &o.mem); @@ -588,7 +1079,8 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const u.block = CreateBlock(vaddr, size, vaddr_num); u.info = o; u.others.Clear(); - updated = true; + u.scenario = scenario; + updated = true; break; } index++; @@ -600,7 +1092,8 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const h.block = CreateBlock(vaddr, size, vaddr_num); h.info = o; h.others.Clear(); - h.free = false; + h.scenario = scenario; + h.free = false; m_objects.Add(h); } @@ -608,15 +1101,17 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const { for (const auto& obj: others) { - Link(index, obj.object_id, obj.relation); + Link(index, obj.object_id, obj.relation, scenario); } } return o.object.obj; } -Vector GpuMemory::FindObjects(const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +Vector GpuMemory::FindObjects(const uint64_t* vaddr, const uint64_t* size, int vaddr_num, bool exact) { + KYTY_PROFILER_BLOCK("GpuMemory::FindObjects", profiler::colors::Green200); + EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num > VADDR_BLOCKS_MAX || vaddr_num <= 0); Core::LockGuard lock(m_mutex); @@ -625,19 +1120,19 @@ Vector GpuMemory::FindObjects(const uint64_t* vaddr, const uint Vector ret; - printf("GpuMemory::FindObjects()\n"); + // printf("GpuMemory::FindObjects()\n"); - for (int i = 0; i < vaddr_num; i++) - { - printf("\t vaddr = %016" PRIx64 ", size = %016" PRIx64 "\n", vaddr[i], size[i]); - } + // for (int i = 0; i < vaddr_num; i++) + // { + // printf("\t vaddr = %016" PRIx64 ", size = %016" PRIx64 "\n", vaddr[i], size[i]); + // } for (const auto& obj: objects) { const auto& h = m_objects[obj.object_id]; EXIT_IF(h.free); - printf("\t %s, %d, %s\n", Core::EnumName(obj.relation).C_Str(), obj.object_id, Core::EnumName(h.info.object.type).C_Str()); - if (obj.relation == OverlapType::Equals) + // printf("\t %s, %d, %s\n", Core::EnumName(obj.relation).C_Str(), obj.object_id, Core::EnumName(h.info.object.type).C_Str()); + if (obj.relation == OverlapType::Equals || (!exact && obj.relation == OverlapType::IsContainedWithin)) { ret.Add(h.info.object); } @@ -661,14 +1156,14 @@ void GpuMemory::ResetHash(GraphicContext* /*ctx*/, const uint64_t* vaddr, const { for (const auto& obj: object_ids) { - EXIT_NOT_IMPLEMENTED(obj.relation != OverlapType::Equals); - auto& h = m_objects[obj.object_id]; EXIT_IF(h.free); auto& o = h.info; if (o.object.type == type) { + EXIT_NOT_IMPLEMENTED(obj.relation != OverlapType::Equals); + for (int vi = 0; vi < vaddr_num; vi++) { printf("ResetHash: type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 ", old_hash = 0x%016" PRIx64 @@ -677,12 +1172,15 @@ void GpuMemory::ResetHash(GraphicContext* /*ctx*/, const uint64_t* vaddr, const o.hash[vi] = new_hash; } + o.gpu_update_time = get_current_time(); + g_gpu_memory_watcher->Watch(vaddr, size, vaddr_num, WatchCallback, this, + reinterpret_cast(static_cast(obj.object_id))); } } } } -void GpuMemory::Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size) +void GpuMemory::Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size, bool unmap) { Core::LockGuard lock(m_mutex); @@ -690,20 +1188,23 @@ void GpuMemory::Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size) printf("\t gpu_vaddr = 0x%016" PRIx64 "\n", vaddr); printf("\t size = 0x%016" PRIx64 "\n", size); - EXIT_NOT_IMPLEMENTED(!IsAllocated(vaddr, size)); - - int index = 0; - for (auto& a: m_allocated) + if (unmap) { - if (a.vaddr == vaddr && a.size == size) - { - m_allocated.RemoveAt(index); - break; - } - index++; - } + EXIT_NOT_IMPLEMENTED(!IsAllocated(vaddr, size)); - EXIT_NOT_IMPLEMENTED(IsAllocated(vaddr, size)); + int index = 0; + for (auto& a: m_allocated) + { + if (a.vaddr == vaddr && a.size == size) + { + m_allocated.RemoveAt(index); + break; + } + index++; + } + + EXIT_NOT_IMPLEMENTED(IsAllocated(vaddr, size)); + } auto object_ids = FindBlocks(&vaddr, &size, 1); @@ -722,13 +1223,13 @@ void GpuMemory::Free(GraphicContext* ctx, int object_id) { auto& h = m_objects[object_id]; EXIT_IF(h.free); - auto& o = h.info; + auto& o = h.info; + const auto& block = h.block; EXIT_IF(o.delete_func == nullptr); if (o.delete_func != nullptr) { - const auto& block = h.block; // EXIT_IF(block.free); for (int vi = 0; vi < block.vaddr_num; vi++) { @@ -737,6 +1238,7 @@ void GpuMemory::Free(GraphicContext* ctx, int object_id) } o.delete_func(ctx, o.object.obj, &o.mem); } + g_gpu_memory_watcher->Stop(block.vaddr, block.size, block.vaddr_num); h.free = true; DeleteBlock(&h.block); } @@ -744,6 +1246,8 @@ void GpuMemory::Free(GraphicContext* ctx, int object_id) // NOLINTNEXTLINE(readability-function-cognitive-complexity) Vector GpuMemory::FindBlocks(const uint64_t* vaddr, const uint64_t* size, int vaddr_num) { + KYTY_PROFILER_BLOCK("GpuMemory::FindBlocks", profiler::colors::Green100); + EXIT_IF(vaddr_num <= 0 || vaddr_num > VADDR_BLOCKS_MAX); EXIT_IF(vaddr == nullptr || size == nullptr); @@ -752,7 +1256,7 @@ Vector GpuMemory::FindBlocks(const uint64_t* vaddr, if (vaddr_num != 1) { int index = 0; - for (auto& b: m_objects) + for (const auto& b: m_objects) { if (!b.free) { @@ -797,7 +1301,7 @@ Vector GpuMemory::FindBlocks(const uint64_t* vaddr, } else { int index = 0; - for (auto& b: m_objects) + for (const auto& b: m_objects) { if (!b.free) { @@ -873,23 +1377,9 @@ void GpuMemory::WriteBack(GraphicContext* ctx) auto& block = h.block; // EXIT_IF(block.free); + g_gpu_memory_watcher->Stop(block.vaddr, block.size, block.vaddr_num); o.write_back_func(ctx, o.object.obj, block.vaddr, block.size, block.vaddr_num); - - for (int vi = 0; vi < block.vaddr_num; vi++) - { - uint64_t new_hash = 0; - - if (o.check_hash) - { - new_hash = calc_hash(reinterpret_cast(block.vaddr[vi]), block.size[vi]); - } - - printf("WriteBack (GPU -> CPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 ", old_hash = 0x%016" PRIx64 - ", new_hash = 0x%016" PRIx64 "\n", - Core::EnumName(o.object.type).C_Str(), block.vaddr[vi], block.size[vi], o.hash[vi], new_hash); - - o.hash[vi] = new_hash; - } + o.cpu_update_time = get_current_time(); if (!h.others.IsEmpty()) { @@ -898,7 +1388,35 @@ void GpuMemory::WriteBack(GraphicContext* ctx) auto& o2 = m_objects[h.others.At(0).object_id].info; - Update(ctx, o2, block.vaddr, block.size, block.vaddr_num, o.hash); + o2.cpu_update_time = o.cpu_update_time; + + Update(ctx, h.others.At(0).object_id); + + for (int vi = 0; vi < block.vaddr_num; vi++) + { + printf("WriteBack (GPU -> CPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 + ", old_hash = 0x%016" PRIx64 ", new_hash = 0x%016" PRIx64 "\n", + Core::EnumName(o.object.type).C_Str(), block.vaddr[vi], block.size[vi], o.hash[vi], o2.hash[vi]); + + o.hash[vi] = o2.hash[vi]; + } + } else + { + for (int vi = 0; vi < block.vaddr_num; vi++) + { + uint64_t new_hash = 0; + + if (o.check_hash) + { + new_hash = calc_hash(reinterpret_cast(block.vaddr[vi]), block.size[vi]); + } + + printf("WriteBack (GPU -> CPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 + ", old_hash = 0x%016" PRIx64 ", new_hash = 0x%016" PRIx64 "\n", + Core::EnumName(o.object.type).C_Str(), block.vaddr[vi], block.size[vi], o.hash[vi], new_hash); + + o.hash[vi] = new_hash; + } } o.in_use = false; @@ -912,6 +1430,7 @@ void GpuMemory::Flush(GraphicContext* ctx) { Core::LockGuard lock(m_mutex); + int index = 0; for (auto& h: m_objects) { if (!h.free) @@ -923,7 +1442,11 @@ void GpuMemory::Flush(GraphicContext* ctx) EXIT_IF(o.update_func == nullptr); o.update_func(ctx, o.params, o.object.obj, block.vaddr, block.size, block.vaddr_num); + o.gpu_update_time = get_current_time(); + g_gpu_memory_watcher->Watch(block.vaddr, block.size, block.vaddr_num, WatchCallback, this, + reinterpret_cast(static_cast(index))); } + index++; } } @@ -954,11 +1477,13 @@ CREATE TABLE [objects]( [param5] INT64, [param6] INT64, [param7] INT64, - [other_rel] TEXT, - [other_id] INTEGER REFERENCES [objects]([id]), + [scenario] TEXT, + [others] TEXT, [hash] TEXT, [hash2] TEXT, [hash3] TEXT, + [gpu_update_time] INT64, + [cpu_update_time] INT64, [write_back_func] TEXT, [delete_func] TEXT, [update_func] TEXT, @@ -986,19 +1511,22 @@ CREATE TABLE [ranges]( m_db_add_object = m_db.Prepare( "insert into objects(dump_id, id, vaddr, vaddr2, vaddr3, size, size2, size3, obj, param0, param1, param2, param3, param4, " "param5, param6, param7, type, hash, hash2, " - "hash3, other_rel, other_id, write_back_func, delete_func, update_func, use_last_frame, use_num, in_use, read_only, " + "hash3, gpu_update_time, cpu_update_time, scenario, others, write_back_func, delete_func, update_func, use_last_frame, " + "use_num, in_use, read_only, " "check_hash, vk_mem_size, " "vk_mem_alignment, vk_mem_memoryTypeBits, vk_mem_property, vk_mem_memory, vk_mem_offset, vk_mem_type, vk_mem_unique_id) " "values(:dump_id, :id, :vaddr, :vaddr2, :vaddr3, :size, :size2, :size3, :obj, :param0, :param1, :param2, :param3, :param4, " ":param5, " ":param6, :param7, :type, :hash, " - ":hash2, :hash3, :other_rel, :other_id, :write_back_func, :delete_func, :update_func, :use_last_frame, :use_num, :in_use, " + ":hash2, :hash3, :gpu_update_time, :cpu_update_time, :scenario, :others, :write_back_func, :delete_func, :update_func, " + ":use_last_frame, :use_num, :in_use, " ":read_only, :check_hash, " ":vk_mem_size, :vk_mem_alignment, :vk_mem_memoryTypeBits, :vk_mem_property, :vk_mem_memory, :vk_mem_offset, :vk_mem_type, " ":vk_mem_unique_id)"); } } +// NOLINTNEXTLINE(readability-function-cognitive-complexity) void GpuMemory::DbgDbDump() { KYTY_PROFILER_FUNCTION(); @@ -1073,15 +1601,21 @@ void GpuMemory::DbgDbDump() m_db_add_object->BindInt64(":vk_mem_offset", static_cast(r.info.mem.offset)); m_db_add_object->BindInt(":vk_mem_type", static_cast(r.info.mem.type)); m_db_add_object->BindInt64(":vk_mem_unique_id", static_cast(r.info.mem.unique_id)); + m_db_add_object->BindString(":scenario", Core::EnumName(r.scenario).C_Str()); + m_db_add_object->BindInt64(":gpu_update_time", static_cast(r.info.gpu_update_time)); + m_db_add_object->BindInt64(":cpu_update_time", static_cast(r.info.cpu_update_time)); if (r.others.Size() > 0) { - m_db_add_object->BindString(":other_rel", Core::EnumName(r.others.At(0).relation)); - m_db_add_object->BindInt(":other_id", id(dump_id, r.others.At(0).object_id)); + Core::StringList others; + for (const auto& s: r.others) + { + others.Add(String::FromPrintf("[%s,%d]", Core::EnumName(s.relation).C_Str(), id(dump_id, s.object_id))); + } + m_db_add_object->BindString(":others", others.Concat(U',')); } else { - m_db_add_object->BindNull(":other_rel"); - m_db_add_object->BindNull(":other_id"); + m_db_add_object->BindNull(":others"); } m_db_add_object->Step(); @@ -1114,69 +1648,15 @@ void GpuMemory::DbgDbSave(const String& file_name) } } -void GpuMemory::DbgDump() -{ - Core::LockGuard lock(m_mutex); - - printf("--- Gpu Memory ---\n"); - - for (auto& o: m_allocated) - { - printf("Allocated block: vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", o.vaddr, o.size); - } - - printf("m_current_frame = %" PRIu64 "\n", m_current_frame); - printf("m_objects_size = %" PRIu64 "\n", m_objects_size); - - for (auto& h: m_objects) - { - if (!h.free) - { - auto& block = h.block; - // EXIT_IF(block.free); - - printf("Object:\n"); - for (int vi = 0; vi < block.vaddr_num; vi++) - { - printf("\t vaddr = 0x%016" PRIx64 "\n", block.vaddr[vi]); - printf("\t size = 0x%016" PRIx64 "\n", block.size[vi]); - GpuResources::Info res_info; - if (g_gpu_resources->FindInfo(block.vaddr[vi], &res_info)) - { - printf("\t {\n"); - printf("\t\t RegisteredResource: %s\n", res_info.name.C_Str()); - printf("\t\t addr: %016" PRIx64 "\n", res_info.memory); - printf("\t\t size: %" PRIu64 "\n", res_info.size); - printf("\t\t type: %" PRIu32 "\n", res_info.type); - printf("\t\t user_data: %" PRIu64 "\n", res_info.user_data); - printf("\t }\n"); - } - } - auto& o = h.info; - printf("\t type = %s\n", Core::EnumName(o.object.type).C_Str()); - for (int vi = 0; vi < block.vaddr_num; vi++) - { - printf("\t hash = 0x%016" PRIx64 "\n", o.hash[vi]); - } - printf("\t vk_size = 0x%016" PRIx64 "\n", o.mem.requirements.size); - printf("\t vk_align = 0x%016" PRIx64 "\n", o.mem.requirements.alignment); - printf("\t vk_type = 0x%08" PRIx32 "\n", o.mem.type); - printf("\t use_last_frame = %" PRIu64 "\n", o.use_last_frame); - printf("\t use_num = %" PRIu64 "\n", o.use_num); - printf("\t in_use = %s\n", o.in_use ? "true" : "false"); - printf("\t read_only = %s\n", o.read_only ? "true" : "false"); - printf("\t check_hash = %s\n", o.check_hash ? "true" : "false"); - } - } -} - void GpuMemoryInit() { EXIT_IF(g_gpu_memory != nullptr); EXIT_IF(g_gpu_resources != nullptr); + EXIT_IF(g_gpu_memory_watcher != nullptr); - g_gpu_memory = new GpuMemory; - g_gpu_resources = new GpuResources; + g_gpu_memory = new GpuMemory; + g_gpu_resources = new GpuResources; + g_gpu_memory_watcher = new MemoryWatcher; } void GpuMemorySetAllocatedRange(uint64_t vaddr, uint64_t size) @@ -1186,35 +1666,36 @@ void GpuMemorySetAllocatedRange(uint64_t vaddr, uint64_t size) g_gpu_memory->SetAllocatedRange(vaddr, size); } -void GpuMemoryFree(GraphicContext* ctx, uint64_t vaddr, uint64_t size) +void GpuMemoryFree(GraphicContext* ctx, uint64_t vaddr, uint64_t size, bool unmap) { EXIT_IF(g_gpu_memory == nullptr); EXIT_IF(ctx == nullptr); - g_gpu_memory->Free(ctx, vaddr, size); + g_gpu_memory->Free(ctx, vaddr, size, unmap); } -void* GpuMemoryCreateObject(GraphicContext* ctx, uint64_t vaddr, uint64_t size, const GpuObject& info) +void* GpuMemoryCreateObject(GraphicContext* ctx, CommandBuffer* buffer, uint64_t vaddr, uint64_t size, const GpuObject& info) { EXIT_IF(g_gpu_memory == nullptr); EXIT_IF(ctx == nullptr); - return g_gpu_memory->CreateObject(ctx, &vaddr, &size, 1, info); + return g_gpu_memory->CreateObject(ctx, buffer, &vaddr, &size, 1, info); } -void* GpuMemoryCreateObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info) +void* GpuMemoryCreateObject(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + const GpuObject& info) { EXIT_IF(g_gpu_memory == nullptr); EXIT_IF(ctx == nullptr); - return g_gpu_memory->CreateObject(ctx, vaddr, size, vaddr_num, info); + return g_gpu_memory->CreateObject(ctx, buffer, vaddr, size, vaddr_num, info); } -Vector GpuMemoryFindObjects(uint64_t vaddr, uint64_t size) +Vector GpuMemoryFindObjects(uint64_t vaddr, uint64_t size, bool exact) { EXIT_IF(g_gpu_memory == nullptr); - return g_gpu_memory->FindObjects(&vaddr, &size, 1); + return g_gpu_memory->FindObjects(&vaddr, &size, 1, exact); } void GpuMemoryResetHash(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, GpuMemoryObjectType type) @@ -1230,7 +1711,6 @@ void GpuMemoryDbgDump() EXIT_IF(g_gpu_memory == nullptr); // g_gpu_memory->DbgDbDump(); - // g_gpu_memory->DbgDump(); // g_gpu_memory->DbgDbSave(U"_gpu_memory.db"); } @@ -1259,6 +1739,13 @@ void GpuMemoryWriteBack(GraphicContext* ctx) g_gpu_memory->WriteBack(ctx); } +bool GpuMemoryCheckAccessViolation(uint64_t vaddr, uint64_t size) +{ + EXIT_IF(g_gpu_memory_watcher == nullptr); + + return g_gpu_memory_watcher->Check(vaddr, size); +} + bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* mem) { static std::atomic seq = 0; diff --git a/source/emulator/src/Graphics/Objects/RenderTexture.cpp b/source/emulator/src/Graphics/Objects/RenderTexture.cpp index 7f4a194..b2cc07b 100644 --- a/source/emulator/src/Graphics/Objects/RenderTexture.cpp +++ b/source/emulator/src/Graphics/Objects/RenderTexture.cpp @@ -1,10 +1,10 @@ #include "Emulator/Graphics/Objects/RenderTexture.h" #include "Kyty/Core/DbgAssert.h" +#include "Kyty/Core/Vector.h" #include "Emulator/Graphics/GraphicContext.h" #include "Emulator/Graphics/GraphicsRender.h" -//#include "Emulator/Graphics/Tile.h" #include "Emulator/Graphics/Utils.h" #include "Emulator/Profiler.h" @@ -66,6 +66,82 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, } } +static void update2_func(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* params, void* obj, GpuMemoryScenario scenario, + const Vector& objects) +{ + KYTY_PROFILER_BLOCK("RenderTextureObject::update_func"); + + EXIT_IF(obj == nullptr); + EXIT_IF(ctx == nullptr); + EXIT_IF(params == nullptr); + EXIT_IF(objects.IsEmpty()); + + auto* vk_obj = static_cast(obj); + + // bool tiled = (params[RenderTextureObject::PARAM_TILED] != 0); + // bool neo = (params[RenderTextureObject::PARAM_NEO] != 0); + // auto pitch = params[RenderTextureObject::PARAM_PITCH]; + auto width = params[RenderTextureObject::PARAM_WIDTH]; + auto height = params[RenderTextureObject::PARAM_HEIGHT]; + + vk_obj->layout = VK_IMAGE_LAYOUT_UNDEFINED; + + if (objects.Size() == 2 && objects.At(0).type == GpuMemoryObjectType::StorageBuffer && + objects.At(1).type == GpuMemoryObjectType::StorageTexture && scenario == GpuMemoryScenario::GenerateMips) + { + auto* src_obj = static_cast(objects.At(1).obj); + + uint32_t mip_width = src_obj->extent.width; + uint32_t mip_height = src_obj->extent.height; + + Vector regions(1); + + bool updated = false; + + for (uint32_t i = 0; i < 16 && !updated; i++) + { + if (mip_width == width && mip_height == height) + { + auto mipmap_offset = UtilCalcMipmapOffset(i, width, height); + + regions[0].src_image = src_obj; + regions[0].src_level = 0; + regions[0].dst_level = 0; + regions[0].width = mip_width; + regions[0].height = mip_height; + regions[0].src_x = mipmap_offset.first; + regions[0].src_y = mipmap_offset.second; + regions[0].dst_x = 0; + regions[0].dst_y = 0; + + if (buffer == nullptr) + { + UtilFillImage(ctx, regions, vk_obj, static_cast(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); + } else + { + UtilImageToImage(buffer, regions, vk_obj, static_cast(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); + } + + updated = true; + } + + if (mip_width > 1) + { + mip_width /= 2; + } + if (mip_height > 1) + { + mip_height /= 2; + } + } + + EXIT_NOT_IMPLEMENTED(!updated); + } else + { + KYTY_NOT_IMPLEMENTED; + } +} + static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) { @@ -168,6 +244,108 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint return vk_obj; } +static void* create2_func(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* params, GpuMemoryScenario scenario, + const Vector& objects, VulkanMemory* mem) +{ + KYTY_PROFILER_BLOCK("RenderTextureObject::CreateFromObjects"); + + EXIT_IF(objects.IsEmpty()); + EXIT_IF(mem == nullptr); + EXIT_IF(ctx == nullptr); + + auto pixel_format = params[RenderTextureObject::PARAM_FORMAT]; + auto width = params[RenderTextureObject::PARAM_WIDTH]; + auto height = params[RenderTextureObject::PARAM_HEIGHT]; + + VkFormat vk_format = VK_FORMAT_UNDEFINED; + + switch (pixel_format) // NOLINT + { + case static_cast(RenderTextureFormat::R8G8B8A8Unorm): vk_format = VK_FORMAT_R8G8B8A8_UNORM; break; + default: EXIT("unknown format: %" PRIu64 "\n", pixel_format); + } + + EXIT_NOT_IMPLEMENTED(width == 0); + EXIT_NOT_IMPLEMENTED(height == 0); + + auto* vk_obj = new RenderTextureVulkanImage; + + vk_obj->extent.width = width; + vk_obj->extent.height = height; + vk_obj->format = vk_format; + vk_obj->image = nullptr; + vk_obj->image_view = nullptr; + + VkImageCreateInfo image_info {}; + image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_info.pNext = nullptr; + image_info.flags = 0; + image_info.imageType = VK_IMAGE_TYPE_2D; + image_info.extent.width = vk_obj->extent.width; + image_info.extent.height = vk_obj->extent.height; + image_info.extent.depth = 1; + image_info.mipLevels = 1; + image_info.arrayLayers = 1; + image_info.format = vk_obj->format; + image_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_info.usage = static_cast(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) | + static_cast(VK_IMAGE_USAGE_TRANSFER_SRC_BIT) | + static_cast(VK_IMAGE_USAGE_TRANSFER_DST_BIT) | + static_cast(VK_IMAGE_USAGE_SAMPLED_BIT); + image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_info.samples = VK_SAMPLE_COUNT_1_BIT; + + vkCreateImage(ctx->device, &image_info, nullptr, &vk_obj->image); + + EXIT_NOT_IMPLEMENTED(vk_obj->image == nullptr); + + vkGetImageMemoryRequirements(ctx->device, vk_obj->image, &mem->requirements); + + mem->property = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + bool allocated = VulkanAllocate(ctx, mem); + + EXIT_NOT_IMPLEMENTED(!allocated); + + VulkanBindImageMemory(ctx, vk_obj, mem); + + vk_obj->memory = *mem; + + printf("RenderTextureObject::CreateFromObjects()\n"); + printf("\t mem->requirements.size = %" PRIu64 "\n", mem->requirements.size); + printf("\t width = %" PRIu64 "\n", width); + printf("\t height = %" PRIu64 "\n", height); + // printf("\t size = %" PRIu64 "\n", *size); + + // EXIT_NOT_IMPLEMENTED(mem->requirements.size > *size); + + update2_func(ctx, buffer, params, vk_obj, scenario, objects); + + VkImageViewCreateInfo create_info {}; + create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + create_info.pNext = nullptr; + create_info.flags = 0; + create_info.image = vk_obj->image; + create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + create_info.format = vk_obj->format; + create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + create_info.subresourceRange.baseArrayLayer = 0; + create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.layerCount = 1; + create_info.subresourceRange.levelCount = 1; + + vkCreateImageView(ctx->device, &create_info, nullptr, &vk_obj->image_view); + + EXIT_NOT_IMPLEMENTED(vk_obj->image_view == nullptr); + + return vk_obj; +} + static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) { KYTY_PROFILER_BLOCK("RenderTextureObject::delete_func"); @@ -202,6 +380,11 @@ GpuObject::create_func_t RenderTextureObject::GetCreateFunc() const return create_func; } +GpuObject::create_from_objects_func_t RenderTextureObject::GetCreateFromObjectsFunc() const +{ + return create2_func; +} + GpuObject::delete_func_t RenderTextureObject::GetDeleteFunc() const { return delete_func; diff --git a/source/emulator/src/Graphics/Objects/StorageBuffer.cpp b/source/emulator/src/Graphics/Objects/StorageBuffer.cpp index 341d3d5..62eaa53 100644 --- a/source/emulator/src/Graphics/Objects/StorageBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/StorageBuffer.cpp @@ -3,6 +3,7 @@ #include "Kyty/Core/DbgAssert.h" #include "Emulator/Graphics/GraphicContext.h" +#include "Emulator/Graphics/GraphicsRender.h" #include "Emulator/Graphics/Utils.h" #include "Emulator/Profiler.h" @@ -21,7 +22,7 @@ static void update_func(GraphicContext* ctx, const uint64_t* /*params*/, void* o EXIT_IF(obj == nullptr); EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); - auto* vk_obj = reinterpret_cast(obj); + auto* vk_obj = reinterpret_cast(obj); void* data = nullptr; // vkMapMemory(ctx->device, vk_obj->memory.memory, vk_obj->memory.offset, *size, 0, &data); @@ -41,7 +42,7 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint EXIT_IF(mem == nullptr); EXIT_IF(ctx == nullptr); - auto* vk_obj = new VulkanBuffer; + auto* vk_obj = new StorageVulkanBuffer; vk_obj->usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; vk_obj->memory.property = static_cast(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | @@ -60,12 +61,17 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* /*mem*/) { KYTY_PROFILER_BLOCK("StorageBufferGpuObject::delete_func"); - auto* vk_obj = reinterpret_cast(obj); + auto* vk_obj = reinterpret_cast(obj); EXIT_IF(vk_obj == nullptr); EXIT_IF(vk_obj->buffer == nullptr); EXIT_IF(ctx == nullptr); + EXIT_IF(vk_obj->cmd_buffer == nullptr); + + // All submitted commands that refer to any element of pDescriptorSets must have completed execution + vk_obj->cmd_buffer->CommandProcessorWait(); + VulkanDeleteBuffer(ctx, vk_obj); delete vk_obj; @@ -79,7 +85,7 @@ static void write_back(GraphicContext* ctx, void* obj, const uint64_t* vaddr, co EXIT_IF(obj == nullptr); EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); - auto* vk_obj = reinterpret_cast(obj); + auto* vk_obj = reinterpret_cast(obj); void* data = nullptr; @@ -123,6 +129,13 @@ GpuObject::update_func_t StorageBufferGpuObject::GetUpdateFunc() const return update_func; } +void StorageBufferSet(CommandBuffer* cmd_buffer, StorageVulkanBuffer* buffer) +{ + // EXIT_IF(buffer->cmd_buffer != nullptr); + + buffer->cmd_buffer = cmd_buffer; +} + } // namespace Kyty::Libs::Graphics #endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Graphics/Objects/StorageTexture.cpp b/source/emulator/src/Graphics/Objects/StorageTexture.cpp index 3949d31..843365c 100644 --- a/source/emulator/src/Graphics/Objects/StorageTexture.cpp +++ b/source/emulator/src/Graphics/Objects/StorageTexture.cpp @@ -133,7 +133,8 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, auto nfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] & 0xffffffffu; auto width = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] >> 32u; auto height = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; - auto levels = params[StorageTextureObject::PARAM_LEVELS]; + // auto base_level = params[StorageTextureObject::PARAM_LEVELS] >> 32u; + auto levels = params[StorageTextureObject::PARAM_LEVELS] & 0xffffffffu; auto pitch = params[StorageTextureObject::PARAM_PITCH]; bool neo = Config::IsNeo(); @@ -208,12 +209,15 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint EXIT_IF(ctx == nullptr); EXIT_IF(params == nullptr); - auto dfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] >> 32u; - auto nfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] & 0xffffffffu; - auto width = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] >> 32u; - auto height = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; - auto levels = params[StorageTextureObject::PARAM_LEVELS]; - auto swizzle = params[StorageTextureObject::PARAM_SWIZZLE]; + auto dfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] >> 32u; + auto nfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] & 0xffffffffu; + auto width = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] >> 32u; + auto height = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; + auto base_level = params[StorageTextureObject::PARAM_LEVELS] >> 32u; + auto levels = params[StorageTextureObject::PARAM_LEVELS] & 0xffffffffu; + auto swizzle = params[StorageTextureObject::PARAM_SWIZZLE]; + + EXIT_NOT_IMPLEMENTED(base_level != 0); VkImageUsageFlags vk_usage = get_usage(); @@ -230,10 +234,7 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint EXIT_NOT_IMPLEMENTED(width == 0); EXIT_NOT_IMPLEMENTED(height == 0); - if (levels > 1) - { - height += (height > 1 ? height / 2 : 1); - } + auto real_height = ((levels > 1) ? height + (height > 1 ? height / 2 : 1) : height); auto* vk_obj = new StorageTextureVulkanImage; @@ -243,7 +244,7 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint image_info.flags = 0; image_info.imageType = VK_IMAGE_TYPE_2D; image_info.extent.width = width; - image_info.extent.height = height; + image_info.extent.height = real_height; image_info.extent.depth = 1; image_info.mipLevels = 1; image_info.arrayLayers = 1; diff --git a/source/emulator/src/Graphics/Objects/Texture.cpp b/source/emulator/src/Graphics/Objects/Texture.cpp index ea22165..eba21f3 100644 --- a/source/emulator/src/Graphics/Objects/Texture.cpp +++ b/source/emulator/src/Graphics/Objects/Texture.cpp @@ -133,7 +133,7 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, auto nfmt = params[TextureObject::PARAM_DFMT_NFMT] & 0xffffffffu; auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u; auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; - auto levels = params[TextureObject::PARAM_LEVELS]; + auto levels = params[TextureObject::PARAM_LEVELS] & 0xffffffffu; auto pitch = params[TextureObject::PARAM_PITCH]; bool neo = Config::IsNeo(); @@ -196,7 +196,9 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, } } -static void update2_func(GraphicContext* ctx, const uint64_t* params, void* obj, const Vector& objects) +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +static void update2_func(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* params, void* obj, GpuMemoryScenario scenario, + const Vector& objects) { KYTY_PROFILER_BLOCK("TextureObject::update2_func"); @@ -209,7 +211,7 @@ static void update2_func(GraphicContext* ctx, const uint64_t* params, void* obj, auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u; auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; - auto levels = params[TextureObject::PARAM_LEVELS]; + auto levels = params[TextureObject::PARAM_LEVELS] & 0xffffffffu; VkImageLayout vk_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -220,9 +222,9 @@ static void update2_func(GraphicContext* ctx, const uint64_t* params, void* obj, Vector regions(levels); - if (objects.Size() == 1 && objects.At(0).type == GpuMemoryObjectType::StorageTexture) + if (objects.Size() == 1 && objects.At(0).type == GpuMemoryObjectType::StorageTexture && scenario == GpuMemoryScenario::Common) { - auto* src_obj = static_cast(objects.At(0).obj); + auto* src_obj = static_cast(objects.At(0).obj); for (uint32_t i = 0; i < levels; i++) { @@ -247,10 +249,8 @@ static void update2_func(GraphicContext* ctx, const uint64_t* params, void* obj, mip_height /= 2; } } - } else + } else if (levels == objects.Size() && scenario == GpuMemoryScenario::Common) { - EXIT_NOT_IMPLEMENTED(levels != objects.Size()); - for (uint32_t i = 0; i < levels; i++) { const auto& object = objects.At(i); @@ -278,9 +278,87 @@ static void update2_func(GraphicContext* ctx, const uint64_t* params, void* obj, mip_height /= 2; } } + } else if (objects.Size() >= 2 && objects.At(0).type == GpuMemoryObjectType::StorageBuffer && + objects.At(1).type == GpuMemoryObjectType::StorageTexture && scenario == GpuMemoryScenario::GenerateMips) + { + + for (uint32_t i = 0; i < levels; i++) + { + VulkanImage* src_image = nullptr; + bool storage = false; + + for (const auto& o: objects) + { + if (o.type == GpuMemoryObjectType::StorageTexture) + { + auto* src_obj = static_cast(o.obj); + if (mip_width == src_obj->extent.width && mip_height == src_obj->extent.height) + { + src_image = src_obj; + storage = true; + break; + } + } else if (o.type == GpuMemoryObjectType::RenderTexture) + { + auto* src_obj = static_cast(o.obj); + if (mip_width == src_obj->extent.width && mip_height == src_obj->extent.height) + { + src_image = src_obj; + storage = false; + break; + } + } + } + + EXIT_NOT_IMPLEMENTED(src_image == nullptr); + + if (storage) + { + auto mipmap_offset = UtilCalcMipmapOffset(i, width, height); + + regions[i].src_image = src_image; + regions[i].src_level = 0; + regions[i].dst_level = i; + regions[i].width = mip_width; + regions[i].height = mip_height; + regions[i].src_x = mipmap_offset.first; + regions[i].src_y = mipmap_offset.second; + regions[i].dst_x = 0; + regions[i].dst_y = 0; + } else + { + regions[i].src_image = src_image; + regions[i].src_level = 0; + regions[i].dst_level = i; + regions[i].width = mip_width; + regions[i].height = mip_height; + regions[i].src_x = 0; + regions[i].src_y = 0; + regions[i].dst_x = 0; + regions[i].dst_y = 0; + } + + if (mip_width > 1) + { + mip_width /= 2; + } + if (mip_height > 1) + { + mip_height /= 2; + } + } + } else + { + KYTY_NOT_IMPLEMENTED; } - UtilFillImage(ctx, regions, vk_obj, static_cast(vk_layout)); + if (buffer == nullptr) + { + UtilFillImage(ctx, regions, vk_obj, static_cast(vk_layout)); + } else + { + UtilImageToImage(buffer, regions, vk_obj, static_cast(vk_layout)); + } } static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, @@ -293,12 +371,13 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint EXIT_IF(ctx == nullptr); EXIT_IF(params == nullptr); - auto dfmt = params[TextureObject::PARAM_DFMT_NFMT] >> 32u; - auto nfmt = params[TextureObject::PARAM_DFMT_NFMT] & 0xffffffffu; - auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u; - auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; - auto levels = params[TextureObject::PARAM_LEVELS]; - auto swizzle = params[TextureObject::PARAM_SWIZZLE]; + auto dfmt = params[TextureObject::PARAM_DFMT_NFMT] >> 32u; + auto nfmt = params[TextureObject::PARAM_DFMT_NFMT] & 0xffffffffu; + auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u; + auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; + auto base_level = params[TextureObject::PARAM_LEVELS] >> 32u; + auto levels = params[TextureObject::PARAM_LEVELS] & 0xffffffffu; + auto swizzle = params[TextureObject::PARAM_SWIZZLE]; VkImageUsageFlags vk_usage = get_usage(); @@ -379,7 +458,7 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint create_info.components = components; create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; create_info.subresourceRange.baseArrayLayer = 0; - create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.baseMipLevel = base_level; create_info.subresourceRange.layerCount = 1; create_info.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; @@ -390,7 +469,8 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint return vk_obj; } -static void* create2_func(GraphicContext* ctx, const uint64_t* params, const Vector& objects, VulkanMemory* mem) +static void* create2_func(GraphicContext* ctx, CommandBuffer* buffer, const uint64_t* params, GpuMemoryScenario scenario, + const Vector& objects, VulkanMemory* mem) { KYTY_PROFILER_BLOCK("TextureObject::CreateFromObjects"); @@ -399,12 +479,13 @@ static void* create2_func(GraphicContext* ctx, const uint64_t* params, const Vec EXIT_IF(ctx == nullptr); EXIT_IF(params == nullptr); - auto dfmt = params[TextureObject::PARAM_DFMT_NFMT] >> 32u; - auto nfmt = params[TextureObject::PARAM_DFMT_NFMT] & 0xffffffffu; - auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u; - auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; - auto levels = params[TextureObject::PARAM_LEVELS]; - auto swizzle = params[TextureObject::PARAM_SWIZZLE]; + auto dfmt = params[TextureObject::PARAM_DFMT_NFMT] >> 32u; + auto nfmt = params[TextureObject::PARAM_DFMT_NFMT] & 0xffffffffu; + auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u; + auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; + auto base_level = params[TextureObject::PARAM_LEVELS] >> 32u; + auto levels = params[TextureObject::PARAM_LEVELS] & 0xffffffffu; + auto swizzle = params[TextureObject::PARAM_SWIZZLE]; VkImageUsageFlags vk_usage = get_usage(); @@ -473,7 +554,7 @@ static void* create2_func(GraphicContext* ctx, const uint64_t* params, const Vec vk_obj->memory = *mem; - update2_func(ctx, params, vk_obj, objects); + update2_func(ctx, buffer, params, vk_obj, scenario, objects); VkImageViewCreateInfo create_info {}; create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -485,7 +566,7 @@ static void* create2_func(GraphicContext* ctx, const uint64_t* params, const Vec create_info.components = components; create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; create_info.subresourceRange.baseArrayLayer = 0; - create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.baseMipLevel = base_level; create_info.subresourceRange.layerCount = 1; create_info.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; diff --git a/source/emulator/src/Graphics/Shader.cpp b/source/emulator/src/Graphics/Shader.cpp index c3479ce..d2d53cb 100644 --- a/source/emulator/src/Graphics/Shader.cpp +++ b/source/emulator/src/Graphics/Shader.cpp @@ -802,6 +802,7 @@ KYTY_SHADER_PARSER(shader_parse_vopc) case 0x0d: inst.type = ShaderInstructionType::VCmpNeqF32; break; case 0x0e: inst.type = ShaderInstructionType::VCmpNltF32; break; case 0x0f: inst.type = ShaderInstructionType::VCmpTruF32; break; + case 0x1d: inst.type = ShaderInstructionType::VCmpxNeqF32; break; case 0x80: inst.type = ShaderInstructionType::VCmpFI32; break; case 0x81: inst.type = ShaderInstructionType::VCmpLtI32; break; case 0x82: inst.type = ShaderInstructionType::VCmpEqI32; break; @@ -1096,6 +1097,7 @@ KYTY_SHADER_PARSER(shader_parse_vop3) case 0x0d: inst.type = ShaderInstructionType::VCmpNeqF32; break; case 0x0e: inst.type = ShaderInstructionType::VCmpNltF32; break; case 0x0f: inst.type = ShaderInstructionType::VCmpTruF32; break; + case 0x1d: inst.type = ShaderInstructionType::VCmpxNeqF32; break; case 0x80: inst.type = ShaderInstructionType::VCmpFI32; break; case 0x81: inst.type = ShaderInstructionType::VCmpLtI32; break; case 0x82: inst.type = ShaderInstructionType::VCmpEqI32; break; @@ -1555,6 +1557,17 @@ KYTY_SHADER_PARSER(shader_parse_mimg) inst.dst.size = 4; } break; + case 0x08: + inst.type = ShaderInstructionType::ImageStore; + inst.src[0].size = 3; + inst.src[1].size = 8; + inst.src_num = 2; + if (dmask == 0xf) + { + inst.format = ShaderInstructionFormat::Vdata4Vaddr3StDmaskF; + inst.dst.size = 4; + } + break; case 0x09: inst.type = ShaderInstructionType::ImageStoreMip; inst.src[0].size = 4; @@ -2046,6 +2059,8 @@ static ShaderUsageInfo GetUsageSlots(const uint32_t* code) static void ShaderDetectBuffers(ShaderVertexInputInfo* info) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(info == nullptr); info->buffers_num = 0; @@ -2104,13 +2119,21 @@ static void ShaderDetectBuffers(ShaderVertexInputInfo* info) static void ShaderParseFetch(ShaderVertexInputInfo* info, const uint32_t* fetch, const uint32_t* buffer) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(info == nullptr || fetch == nullptr || buffer == nullptr); + KYTY_PROFILER_BLOCK("ShaderParseFetch::parse_code"); + ShaderCode code; code.SetType(ShaderType::Fetch); shader_parse(0, fetch, nullptr, &code); - printf("%s", code.DbgDump().C_Str()); + KYTY_PROFILER_END_BLOCK; + + // printf("%s", code.DbgDump().C_Str()); + + KYTY_PROFILER_BLOCK("ShaderParseFetch::check_insts"); const auto& insts = code.GetInstructions(); uint32_t size = insts.Size(); @@ -2178,6 +2201,8 @@ static void ShaderParseFetch(ShaderVertexInputInfo* info, const uint32_t* fetch, } } + KYTY_PROFILER_END_BLOCK; + EXIT_NOT_IMPLEMENTED(s_num != v_num); } @@ -2358,6 +2383,8 @@ void ShaderCalcBindingIndices(ShaderBindResources* bind) void ShaderGetInputInfoVS(const VertexShaderInfo* regs, ShaderVertexInputInfo* info) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(info == nullptr || regs == nullptr); info->export_count = static_cast(1 + ((regs->vs_regs.m_spiVsOutConfig >> 1u) & 0x1Fu)); @@ -2379,6 +2406,8 @@ void ShaderGetInputInfoVS(const VertexShaderInfo* regs, ShaderVertexInputInfo* i bool vertex_buffer = false; int vertex_buffer_reg = 0; + KYTY_PROFILER_BLOCK("ShaderGetInputInfoVS::usages_cycle"); + for (int i = 0; i < usages.slots_num; i++) { const auto& usage = usages.slots[i]; @@ -2405,6 +2434,10 @@ void ShaderGetInputInfoVS(const VertexShaderInfo* regs, ShaderVertexInputInfo* i } } + KYTY_PROFILER_END_BLOCK; + + KYTY_PROFILER_BLOCK("ShaderGetInputInfoVS::parse_fetch"); + EXIT_NOT_IMPLEMENTED((fetch && !vertex_buffer) || (!fetch && vertex_buffer)); if (fetch && vertex_buffer) @@ -2425,16 +2458,29 @@ void ShaderGetInputInfoVS(const VertexShaderInfo* regs, ShaderVertexInputInfo* i ShaderDetectBuffers(info); } + KYTY_PROFILER_END_BLOCK; + + KYTY_PROFILER_BLOCK("ShaderGetInputInfoVS::calc_binding"); + ShaderCalcBindingIndices(&info->bind); + + KYTY_PROFILER_END_BLOCK; } // NOLINTNEXTLINE(readability-function-cognitive-complexity) void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputInfo* vs_info, ShaderPixelInputInfo* ps_info) { + KYTY_PROFILER_FUNCTION(); + EXIT_IF(vs_info == nullptr); EXIT_IF(ps_info == nullptr); EXIT_IF(regs == nullptr); + if (regs->ps_embedded) + { + return; + } + ps_info->input_num = regs->ps_regs.ps_in_control; ps_info->ps_pos_xy = (regs->ps_regs.ps_input_ena == 0x00000302 && regs->ps_regs.ps_input_addr == 0x00000302); ps_info->ps_pixel_kill_enable = regs->ps_regs.shader_kill_enable; @@ -2515,6 +2561,7 @@ void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputIn ShaderCalcBindingIndices(&ps_info->bind); } +// NOLINTNEXTLINE(readability-function-cognitive-complexity) void ShaderGetInputInfoCS(const ComputeShaderInfo* regs, ShaderComputeInputInfo* info) { EXIT_IF(info == nullptr); @@ -2564,9 +2611,17 @@ void ShaderGetInputInfoCS(const ComputeShaderInfo* regs, ShaderComputeInputInfo* regs->cs_user_sgpr, extended_buffer); break; case 0x04: - EXIT_NOT_IMPLEMENTED(usage.flags != 0); - ShaderGetStorageBuffer(&info->bind.storage_buffers, usage.start_register, usage.slot, ShaderStorageUsage::ReadWrite, - regs->cs_user_sgpr, extended_buffer); + EXIT_NOT_IMPLEMENTED(usage.flags != 0 && usage.flags != 3); + if (usage.flags == 0) + { + ShaderGetStorageBuffer(&info->bind.storage_buffers, usage.start_register, usage.slot, ShaderStorageUsage::ReadWrite, + regs->cs_user_sgpr, extended_buffer); + } else if (usage.flags == 3) + { + ShaderGetTextureBuffer(&info->bind.textures2D, usage.start_register, usage.slot, ShaderTextureUsage::ReadWrite, + regs->cs_user_sgpr, extended_buffer); + EXIT_NOT_IMPLEMENTED(info->bind.textures2D.textures[info->bind.textures2D.textures_num - 1].Type() != 9); + } break; case 0x07: EXIT_NOT_IMPLEMENTED(usage.flags != 0); @@ -2730,6 +2785,8 @@ static void ShaderDbgDumpResources(const ShaderBindResources& bind) void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info) { + KYTY_PROFILER_BLOCK("ShaderDbgDumpInputInfo(Vs)"); + printf("ShaderDbgDumpInputInfo()\n"); printf("\t fetch = %s\n", info->fetch ? "true" : "false"); @@ -2781,6 +2838,8 @@ void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info) void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo* info) { + KYTY_PROFILER_BLOCK("ShaderDbgDumpInputInfo(Ps)"); + printf("ShaderDbgDumpInputInfo()\n"); printf("\t input_num = %u\n", info->input_num); @@ -2967,8 +3026,8 @@ ShaderCode ShaderParseVS(const VertexShaderInfo* regs) if (regs->vs_embedded) { - code.SetEmbedded(true); - code.SetEmbeddedId(regs->vs_embedded_id); + code.SetVsEmbedded(true); + code.SetVsEmbeddedId(regs->vs_embedded_id); } else { const auto* src = reinterpret_cast(regs->vs_regs.GetGpuAddress()); @@ -3007,9 +3066,9 @@ Vector ShaderRecompileVS(const ShaderCode& code, const ShaderVertexInp Vector ret; ShaderLogHelper log("vs"); - if (code.IsEmbedded()) + if (code.IsVsEmbedded()) { - source = SpirvGetEmbeddedVs(code.GetEmbeddedId()); + source = SpirvGetEmbeddedVs(code.GetVsEmbeddedId()); } else { for (int i = 0; i < input_info->bind.storage_buffers.buffers_num; i++) @@ -3039,32 +3098,39 @@ ShaderCode ShaderParsePS(const PixelShaderInfo* regs) { KYTY_PROFILER_FUNCTION(profiler::colors::Blue300); - const auto* src = reinterpret_cast(regs->ps_regs.data_addr); - - EXIT_NOT_IMPLEMENTED(src == nullptr); - - ps_print("ShaderParsePS()", regs->ps_regs); - ps_check(regs->ps_regs); - - EXIT_NOT_IMPLEMENTED(regs->ps_regs.user_sgpr > regs->ps_user_sgpr.count); - - const auto* header = GetBinaryInfo(src); - - EXIT_NOT_IMPLEMENTED(header == nullptr); - - bi_print("ShaderParsePS():ShaderBinaryInfo", *header); - ShaderCode code; code.SetType(ShaderType::Pixel); - shader_parse(0, src, nullptr, &code); - - if (g_debug_printfs != nullptr) + if (regs->ps_embedded) { - auto id = (static_cast(header->hash0) << 32u) | header->crc32; - if (auto index = g_debug_printfs->Find(id, [](auto cmd, auto id) { return cmd.id == id; }); g_debug_printfs->IndexValid(index)) + code.SetPsEmbedded(true); + code.SetPsEmbeddedId(regs->ps_embedded_id); + } else + { + const auto* src = reinterpret_cast(regs->ps_regs.data_addr); + + EXIT_NOT_IMPLEMENTED(src == nullptr); + + ps_print("ShaderParsePS()", regs->ps_regs); + ps_check(regs->ps_regs); + + EXIT_NOT_IMPLEMENTED(regs->ps_regs.user_sgpr > regs->ps_user_sgpr.count); + + const auto* header = GetBinaryInfo(src); + + EXIT_NOT_IMPLEMENTED(header == nullptr); + + bi_print("ShaderParsePS():ShaderBinaryInfo", *header); + + shader_parse(0, src, nullptr, &code); + + if (g_debug_printfs != nullptr) { - code.GetDebugPrintfs() = g_debug_printfs->At(index).cmds; + auto id = (static_cast(header->hash0) << 32u) | header->crc32; + if (auto index = g_debug_printfs->Find(id, [](auto cmd, auto id) { return cmd.id == id; }); g_debug_printfs->IndexValid(index)) + { + code.GetDebugPrintfs() = g_debug_printfs->At(index).cmds; + } } } @@ -3075,24 +3141,30 @@ Vector ShaderRecompilePS(const ShaderCode& code, const ShaderPixelInpu { KYTY_PROFILER_FUNCTION(profiler::colors::Blue300); - ShaderLogHelper log("ps"); - - for (uint32_t i = 0; i < input_info->input_num; i++) - { - EXIT_NOT_IMPLEMENTED(input_info->interpolator_settings[i] != i); - } - - for (int i = 0; i < input_info->bind.storage_buffers.buffers_num; i++) - { - const auto& r = input_info->bind.storage_buffers.buffers[i]; - EXIT_NOT_IMPLEMENTED(((r.Stride() * r.NumRecords()) & 0x3u) != 0); - } - + String source; Vector ret; + ShaderLogHelper log("ps"); - log.DumpOriginalShader(code); + if (code.IsPsEmbedded()) + { + source = SpirvGetEmbeddedPs(code.GetPsEmbeddedId()); + } else + { + // for (uint32_t i = 0; i < input_info->input_num; i++) + // { + // EXIT_NOT_IMPLEMENTED(input_info->interpolator_settings[i] != i); + // } - auto source = SpirvGenerateSource(code, nullptr, input_info, nullptr); + for (int i = 0; i < input_info->bind.storage_buffers.buffers_num; i++) + { + const auto& r = input_info->bind.storage_buffers.buffers[i]; + EXIT_NOT_IMPLEMENTED(((r.Stride() * r.NumRecords()) & 0x3u) != 0); + } + + log.DumpOriginalShader(code); + + source = SpirvGenerateSource(code, nullptr, input_info, nullptr); + } log.DumpRecompiledShader(source); @@ -3194,7 +3266,8 @@ static ShaderBindParameters ShaderUpdateBindInfo(const ShaderCode& code, const S break; } - if (inst.type == ShaderInstructionType::ImageStoreMip || inst.type == ShaderInstructionType::ImageLoad) + if (inst.type == ShaderInstructionType::ImageStore || inst.type == ShaderInstructionType::ImageStoreMip || + inst.type == ShaderInstructionType::ImageLoad) { if (inst.src[1].register_id == s) { @@ -3389,6 +3462,8 @@ static void ShaderGetBindIds(ShaderId* ret, const ShaderBindResources& bind) ShaderId ShaderGetIdVS(const VertexShaderInfo* regs, const ShaderVertexInputInfo* input_info) { + KYTY_PROFILER_FUNCTION(); + ShaderId ret; if (regs->vs_embedded) @@ -3453,6 +3528,16 @@ ShaderId ShaderGetIdVS(const VertexShaderInfo* regs, const ShaderVertexInputInfo ShaderId ShaderGetIdPS(const PixelShaderInfo* regs, const ShaderPixelInputInfo* input_info) { + KYTY_PROFILER_FUNCTION(); + + ShaderId ret; + + if (regs->ps_embedded) + { + ret.ids.Add(regs->ps_embedded_id); + return ret; + } + const auto* src = reinterpret_cast(regs->ps_regs.data_addr); EXIT_NOT_IMPLEMENTED(src == nullptr); @@ -3461,7 +3546,6 @@ ShaderId ShaderGetIdPS(const PixelShaderInfo* regs, const ShaderPixelInputInfo* EXIT_NOT_IMPLEMENTED(header == nullptr); - ShaderId ret; ret.ids.Expand(64); ret.ids.Add(header->length); diff --git a/source/emulator/src/Graphics/ShaderSpirv.cpp b/source/emulator/src/Graphics/ShaderSpirv.cpp index 58403cc..e3b7419 100644 --- a/source/emulator/src/Graphics/ShaderSpirv.cpp +++ b/source/emulator/src/Graphics/ShaderSpirv.cpp @@ -2383,6 +2383,74 @@ KYTY_RECOMPILER_FUNC(Recompile_ImageLoad_Vdata4Vaddr3StDmaskF) return false; } +KYTY_RECOMPILER_FUNC(Recompile_ImageStore_Vdata4Vaddr3StDmaskF) +{ + const auto& inst = code.GetInstructions().At(index); + const auto* bind_info = spirv->GetBindInfo(); + const auto& bind_params = spirv->GetBindParams(); + + if (bind_info != nullptr && bind_params.textures2d_storage_num > 0) + { + auto dst_value0 = operand_variable_to_str(inst.dst, 0); + auto dst_value1 = operand_variable_to_str(inst.dst, 1); + auto dst_value2 = operand_variable_to_str(inst.dst, 2); + auto dst_value3 = operand_variable_to_str(inst.dst, 3); + + auto src0_value0 = operand_variable_to_str(inst.src[0], 0); + auto src0_value1 = operand_variable_to_str(inst.src[0], 1); + + auto src1_value0 = operand_variable_to_str(inst.src[1], 0); + auto src1_value2 = operand_variable_to_str(inst.src[1], 2); + + EXIT_NOT_IMPLEMENTED(dst_value0.type != SpirvType::Float); + EXIT_NOT_IMPLEMENTED(src0_value0.type != SpirvType::Float); + EXIT_NOT_IMPLEMENTED(src1_value0.type != SpirvType::Uint); + + // TODO() check VSKIP + // TODO() check LOD_CLAMPED + // TODO() swizzle channels + // TODO() convert SRGB -> LINEAR if SRGB format was replaced with UNORM + + static const char32_t* text = UR"( + %t24_ = OpLoad %uint % + %t25_ = OpLoad %uint % + %t143_ = OpShiftRightLogical %uint %t25_ %uint_0 + %t145_ = OpBitwiseAnd %uint %t143_ %uint_0x00003fff + %t146_ = OpIAdd %uint %t145_ %uint_1 + %t149_ = OpShiftRightLogical %uint %t25_ %uint_14 + %t150_ = OpBitwiseAnd %uint %t149_ %uint_0x00003fff + %t151_ = OpIAdd %uint %t150_ %uint_1 + %t26_ = OpAccessChain %_ptr_UniformConstant_ImageL %textures2D_L %t24_ + %t27_ = OpLoad %ImageL %t26_ + %t67_ = OpLoad %float % + %t69_ = OpBitcast %uint %t67_ + %t70_ = OpLoad %float % + %t71_ = OpBitcast %uint %t70_ + %t73_ = OpCompositeConstruct %v2uint %t69_ %t71_ + %t84_ = OpLoad %float % + %t85_ = OpLoad %float % + %t86_ = OpLoad %float % + %t87_ = OpLoad %float % + %t88_ = OpCompositeConstruct %v4float %t84_ %t85_ %t86_ %t87_ + OpImageWrite %t27_ %t73_ %t88_ +)"; + *dst_source += String(text) + .ReplaceStr(U"", String::FromPrintf("%u", index)) + .ReplaceStr(U"", src0_value0.value) + .ReplaceStr(U"", src0_value1.value) + .ReplaceStr(U"", src1_value0.value) + .ReplaceStr(U"", src1_value2.value) + .ReplaceStr(U"", dst_value0.value) + .ReplaceStr(U"", dst_value1.value) + .ReplaceStr(U"", dst_value2.value) + .ReplaceStr(U"", dst_value3.value); + + return true; + } + + return false; +} + KYTY_RECOMPILER_FUNC(Recompile_ImageStoreMip_Vdata4Vaddr4StDmaskF) { const auto& inst = code.GetInstructions().At(index); @@ -3807,6 +3875,60 @@ KYTY_RECOMPILER_FUNC(Recompile_VCmpx_XXX_U32_SmaskVsrc0Vsrc1) return true; } +/* XXX: Neq */ +KYTY_RECOMPILER_FUNC(Recompile_VCmpx_XXX_F32_SmaskVsrc0Vsrc1) +{ + const auto& inst = code.GetInstructions().At(index); + + String load0; + String load1; + + String index_str = String::FromPrintf("%u", index); + + EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.dst)); + + auto dst_value0 = operand_variable_to_str(inst.dst, 0); + auto dst_value1 = operand_variable_to_str(inst.dst, 1); + + EXIT_NOT_IMPLEMENTED(dst_value0.type != SpirvType::Uint); + + EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); + + if (!operand_load_float(spirv, inst.src[0], U"t0_", index_str, &load0)) + { + return false; + } + if (!operand_load_float(spirv, inst.src[1], U"t1_", index_str, &load1)) + { + return false; + } + + // TODO() check VSKIP + // TODO() check EXEC + + static const char32_t* text = UR"( + + + %t2_ = %bool %t0_ %t1_ + %t3_ = OpSelect %uint %t2_ %uint_1 %uint_0 + OpStore % %t3_ + OpStore % %uint_0 + OpStore %exec_lo %t3_ + OpStore %exec_hi %uint_0 + +)"; + *dst_source += String(text) + .ReplaceStr(U"", dst_value0.value) + .ReplaceStr(U"", dst_value1.value) + .ReplaceStr(U"", load0) + .ReplaceStr(U"", load1) + .ReplaceStr(U"", param[0]) + .ReplaceStr(U"", EXECZ) + .ReplaceStr(U"", index_str); + + return true; +} + KYTY_RECOMPILER_FUNC(Recompile_VCndmaskB32_VdstVsrc0Vsrc1Smask2) { const auto& inst = code.GetInstructions().At(index); @@ -3967,8 +4089,8 @@ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_F32_VdstVsrc0Vsrc1Vsrc2) String index_str = String::FromPrintf("%u", index); EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.dst)); - EXIT_NOT_IMPLEMENTED(inst.dst.clamp); - EXIT_NOT_IMPLEMENTED(inst.dst.multiplier != 1.0f); + // EXIT_NOT_IMPLEMENTED(inst.dst.clamp); + // EXIT_NOT_IMPLEMENTED(inst.dst.multiplier != 1.0f); auto dst_value = operand_variable_to_str(inst.dst); @@ -4000,11 +4122,20 @@ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_F32_VdstVsrc0Vsrc1Vsrc2) %exec_lo_u_ = OpLoad %uint %exec_lo %exec_hi_u_ = OpLoad %uint %exec_hi ; unused %exec_lo_b_ = OpINotEqual %bool %exec_lo_u_ %uint_0 - %tdst_ = OpLoad %float % - %tval_ = OpSelect %float %exec_lo_b_ %t_ %tdst_ - OpStore % %tval_ + OpSelectionMerge %tl2_ None + OpBranchConditional %exec_lo_b_ %tl1_ %tl2_ + %tl1_ = OpLabel + OpStore % %t_ + + + OpBranch %tl2_ + %tl2_ = OpLabel )"; *dst_source += String(text) + .ReplaceStr(U"", (inst.dst.multiplier != 1.0f + ? String(MULTIPLY).ReplaceStr(U"", spirv->GetConstantFloat(inst.dst.multiplier)) + : U"")) + .ReplaceStr(U"", (inst.dst.clamp ? CLAMP : U"")) .ReplaceStr(U"", dst_value.value) .ReplaceStr(U"", load0) .ReplaceStr(U"", load1) @@ -4690,6 +4821,7 @@ static RecompilerFunc g_recomp_func[] = { {Recompile_ImageLoad_Vdata4Vaddr3StDmaskF, ShaderInstructionType::ImageLoad, ShaderInstructionFormat::Vdata4Vaddr3StDmaskF, {U""}}, {Recompile_ImageSample_Vdata3Vaddr3StSsDmask7, ShaderInstructionType::ImageSample, ShaderInstructionFormat::Vdata3Vaddr3StSsDmask7, {U""}}, {Recompile_ImageSample_Vdata4Vaddr3StSsDmaskF, ShaderInstructionType::ImageSample, ShaderInstructionFormat::Vdata4Vaddr3StSsDmaskF, {U""}}, + {Recompile_ImageStore_Vdata4Vaddr3StDmaskF, ShaderInstructionType::ImageStore, ShaderInstructionFormat::Vdata4Vaddr3StDmaskF, {U""}}, {Recompile_ImageStoreMip_Vdata4Vaddr4StDmaskF, ShaderInstructionType::ImageStoreMip, ShaderInstructionFormat::Vdata4Vaddr4StDmaskF, {U""}}, {Recompile_SBufferLoadDword_SdstSvSoffset, ShaderInstructionType::SBufferLoadDword, ShaderInstructionFormat::SdstSvSoffset, {U""}}, @@ -4701,7 +4833,7 @@ static RecompilerFunc g_recomp_func[] = { {Recompile_SCbranchExecz_Label, ShaderInstructionType::SCbranchExecz, ShaderInstructionFormat::Label, {U""}}, {Recompile_SCbranchScc0_Label, ShaderInstructionType::SCbranchScc0, ShaderInstructionFormat::Label, {U""}}, - {Recompile_SEndpgm_Empty, ShaderInstructionType::SEndpgm, ShaderInstructionFormat::Empty, {U""}}, + {Recompile_SEndpgm_Empty, ShaderInstructionType::SEndpgm, ShaderInstructionFormat::Empty, {U""}}, {Recompile_SLoadDwordx4_Sdst4SbaseSoffset, ShaderInstructionType::SLoadDwordx4, ShaderInstructionFormat::Sdst4SbaseSoffset, {U""}}, {Recompile_SLoadDwordx8_Sdst8SbaseSoffset, ShaderInstructionType::SLoadDwordx8, ShaderInstructionFormat::Sdst8SbaseSoffset, {U""}}, @@ -4744,51 +4876,51 @@ static RecompilerFunc g_recomp_func[] = { {Recompile_S_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SLshrB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpShiftRightLogical %uint %t0_ %ts_"}, SccCheck::NonZero}, {Recompile_S_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAddI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpIAdd %int %t0_ %t1_"}, SccCheck::Overflow}, {Recompile_S_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SMulI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpIMul %int %t0_ %t1_"}, SccCheck::None}, - {Recompile_S_XXX_U32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAddcU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tscc_ = OpLoad %uint %scc", U"%ts_ = OpFunctionCall %v2uint %addc %t0_ %t1_ %tscc_", U"%t_ = OpCompositeExtract %uint %ts_ 0", U"%carry_ = OpCompositeExtract %uint %ts_ 1"}, SccCheck::CarryOut}, - {Recompile_S_XXX_U32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAddU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpIAddCarry %ResTypeU %t0_ %t1_", U"%t_ = OpCompositeExtract %uint %ts_ 0", U"%carry_ = OpCompositeExtract %uint %ts_ 1"}, SccCheck::CarryOut}, + {Recompile_S_XXX_U32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAddcU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tscc_ = OpLoad %uint %scc", U"%ts_ = OpFunctionCall %v2uint %addc %t0_ %t1_ %tscc_", U"%t_ = OpCompositeExtract %uint %ts_ 0", U"%carry_ = OpCompositeExtract %uint %ts_ 1"}, SccCheck::CarryOut}, + {Recompile_S_XXX_U32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAddU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpIAddCarry %ResTypeU %t0_ %t1_", U"%t_ = OpCompositeExtract %uint %ts_ 0", U"%carry_ = OpCompositeExtract %uint %ts_ 1"}, SccCheck::CarryOut}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VAndB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseAnd %uint %t0_ %t1_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VBcntU32B32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tb_ = OpBitCount %int %t0_", U"%tbu_ = OpBitcast %uint %tb_", U"%t_ = OpIAdd %uint %tbu_ %t1_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshlB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpShiftLeftLogical %uint %t0_ %ts_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VBcntU32B32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tb_ = OpBitCount %int %t0_", U"%tbu_ = OpBitcast %uint %tb_", U"%t_ = OpIAdd %uint %tbu_ %t1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshlB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpShiftLeftLogical %uint %t0_ %ts_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshlrevB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%t_ = OpShiftLeftLogical %uint %t1_ %ts_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshrB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpShiftRightLogical %uint %t0_ %ts_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshrrevB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%t_ = OpShiftRightLogical %uint %t1_ %ts_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulHiU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %uint %mul_hi_uint %t0_ %t1_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulLoU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %uint %mul_lo_uint %t0_ %t1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulHiU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %uint %mul_hi_uint %t0_ %t1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulLoU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %uint %mul_lo_uint %t0_ %t1_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulU32U24, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tu0_ = OpBitwiseAnd %uint %t0_ %uint_0x00ffffff", U"%tu1_ = OpBitwiseAnd %uint %t1_ %uint_0x00ffffff", U"%t_ = OpFunctionCall %uint %mul_lo_uint %tu0_ %tu1_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VOrB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseOr %uint %t0_ %t1_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VXorB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseXor %uint %t0_ %t1_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VBfmB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tcount_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%toffset_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpBitFieldInsert %uint %uint_0 %uint_0xffffffff %toffset_ %tcount_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VOrB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseOr %uint %t0_ %t1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VXorB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseXor %uint %t0_ %t1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VBfmB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tcount_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%toffset_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpBitFieldInsert %uint %uint_0 %uint_0xffffffff %toffset_ %tcount_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMacF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpExtInst %float %GLSL_std_450 Fma %t0_ %t1_ %tdst_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMaxF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpExtInst %float %GLSL_std_450 FMax %t0_ %t1_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMinF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpExtInst %float %GLSL_std_450 FMin %t0_ %t1_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFMul %float %t0_ %t1_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VSubF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFSub %float %t0_ %t1_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VSubrevF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFSub %float %t1_ %t0_"}}, - {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VAshrI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %int %t1_ %int_31", U"%t_ = OpShiftRightArithmetic %int %t0_ %ts_"}}, - {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VAshrrevI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %int %t0_ %int_31", U"%t_ = OpShiftRightArithmetic %int %t1_ %ts_"}}, - {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulLoI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %int %mul_lo_int %t0_ %t1_"}}, + {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VAshrI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %int %t1_ %int_31", U"%t_ = OpShiftRightArithmetic %int %t0_ %ts_"}}, + {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VAshrrevI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %int %t0_ %int_31", U"%t_ = OpShiftRightArithmetic %int %t1_ %ts_"}}, + {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulLoI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %int %mul_lo_int %t0_ %t1_"}}, {Recompile_VCvtPkrtzF16F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VCvtPkrtzF16F32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U""}}, {Recompile_VMbcntHiU32B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMbcntHiU32B32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U""}}, {Recompile_VMbcntLoU32B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMbcntLoU32B32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U""}}, {Recompile_SMovB32_SVdstSVsrc0, ShaderInstructionType::SMovB32, ShaderInstructionFormat::SVdstSVsrc0, {U""}}, - {Recompile_SMovB32_SVdstSVsrc0, ShaderInstructionType::SMovkI32, ShaderInstructionFormat::SVdstSVsrc0, {U""}}, - {Recompile_V_XXX_B32_SVdstSVsrc0, ShaderInstructionType::VBfrevB32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpBitReverse %uint %t0_"}}, + {Recompile_SMovB32_SVdstSVsrc0, ShaderInstructionType::SMovkI32, ShaderInstructionFormat::SVdstSVsrc0, {U""}}, + {Recompile_V_XXX_B32_SVdstSVsrc0, ShaderInstructionType::VBfrevB32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpBitReverse %uint %t0_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0, ShaderInstructionType::VNotB32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpNot %uint %t0_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VRcpF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpFDiv %float %float_1_000000 %t0_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VRsqF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 InverseSqrt %t0_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VSqrtF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Sqrt %t0_"}}, - {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VCeilF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Ceil %t0_"}}, - {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VFloorF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Floor %t0_"}}, - {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VFractF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Fract %t0_"}}, - {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VRndneF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 RoundEven %t0_"}}, - {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VTruncF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Trunc %t0_"}}, - {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VCosF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%tr_ = OpFMul %float %t0_ %float_2pi", U"%t_ = OpExtInst %float %GLSL_std_450 Cos %tr_"}}, - {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VExpF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Exp2 %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VCeilF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Ceil %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VFloorF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Floor %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VFractF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Fract %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VRndneF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 RoundEven %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VTruncF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Trunc %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VCosF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%tr_ = OpFMul %float %t0_ %float_2pi", U"%t_ = OpExtInst %float %GLSL_std_450 Cos %tr_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VExpF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Exp2 %t0_"}}, {Recompile_VCvt_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VCvtU32F32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t1_ = OpExtInst %float %GLSL_std_450 Trunc %t0_", U"%t2_ = OpConvertFToU %uint %t1_"}}, - {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32F16, ShaderInstructionFormat::SVdstSVsrc0, {U"%ts_ = OpExtInst %v2float %GLSL_std_450 UnpackHalf2x16 %t0_", U"%t_ = OpCompositeExtract %float %ts_ 0"}}, - {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32I32, ShaderInstructionFormat::SVdstSVsrc0, {U"%ti_ = OpBitcast %int %t0_", U"%t_ = OpConvertSToF %float %ti_"}}, + {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32F16, ShaderInstructionFormat::SVdstSVsrc0, {U"%ts_ = OpExtInst %v2float %GLSL_std_450 UnpackHalf2x16 %t0_", U"%t_ = OpCompositeExtract %float %ts_ 0"}}, + {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32I32, ShaderInstructionFormat::SVdstSVsrc0, {U"%ti_ = OpBitcast %int %t0_", U"%t_ = OpConvertSToF %float %ti_"}}, {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32U32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpConvertUToF %float %t0_"}}, {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32Ubyte0, ShaderInstructionFormat::SVdstSVsrc0, {U"%tb_ = OpBitFieldUExtract %uint %t0_ %uint_0 %uint_8", U"%t_ = OpConvertUToF %float %tb_"}}, {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32Ubyte1, ShaderInstructionFormat::SVdstSVsrc0, {U"%tb_ = OpBitFieldUExtract %uint %t0_ %uint_8 %uint_8", U"%t_ = OpConvertUToF %float %tb_"}}, @@ -4811,54 +4943,55 @@ static RecompilerFunc g_recomp_func[] = { {Recompile_V_XXX_U32_VdstSdst2Vsrc0Vsrc1, ShaderInstructionType::VSubrevI32, ShaderInstructionFormat::VdstSdst2Vsrc0Vsrc1, {U"%t_ = OpISubBorrow %ResTypeU %t1_ %t0_"}}, {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpEqF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdGreaterThanEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdGreaterThan"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdGreaterThanEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdGreaterThan"}}, {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdLessThanEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLgF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdNotEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdLessThan"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLgF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdNotEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdLessThan"}}, {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNeqF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordNotEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNgeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordLessThan"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNgtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordLessThanEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNleF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordGreaterThan"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNlgF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNltF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordGreaterThanEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpOF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFunctionCall %bool %ordered %t0_ %t1_ ; "}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTruF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpUF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFunctionCall %bool %unordered %t0_ %t1_ ; "}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNgeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordLessThan"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNgtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordLessThanEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNleF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordGreaterThan"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNlgF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNltF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordGreaterThanEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpOF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFunctionCall %bool %ordered %t0_ %t1_ ; "}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTruF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpUF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFunctionCall %bool %unordered %t0_ %t1_ ; "}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpEqI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual"}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpEqU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual"}}, - {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, - {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSGreaterThanEqual"}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSGreaterThanEqual"}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGtI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSGreaterThan"}}, - {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLeI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSLessThanEqual"}}, - {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSLessThan"}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLeI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSLessThanEqual"}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSLessThan"}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNeI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpINotEqual"}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpINotEqual"}}, - {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, - {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, - {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThanEqual"}}, - {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGtU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThan"}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThanEqual"}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGtU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThan"}}, {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpULessThanEqual"}}, - {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpULessThan"}}, - {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpULessThan"}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, + {Recompile_VCmpx_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxNeqF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordNotEqual"}}, {Recompile_VCmpx_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxEqU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual"}}, {Recompile_VCmpx_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxNeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpINotEqual"}}, + {Recompile_VCmpx_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxGeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThanEqual"}}, {Recompile_VCmpx_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxGtU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThan"}}, - {Recompile_VCmpx_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxGeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThanEqual"}}, - {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpEqI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpIEqual"}}, - {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGeI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSGreaterThanEqual"}}, - {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGtI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSGreaterThan"}}, - {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLgI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpINotEqual"}}, - {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLtI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSLessThan"}}, - {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLeI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSLessThanEqual"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpEqI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpIEqual"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGeI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSGreaterThanEqual"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGtI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSGreaterThan"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLgI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpINotEqual"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLtI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSLessThan"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLeI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSLessThanEqual"}}, {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpEqU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpIEqual"}}, - {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGeU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpUGreaterThanEqual"}}, - {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGtU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpUGreaterThan"}}, - {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLeU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpULessThanEqual"}}, - {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLtU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpULessThan"}}, - {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLgU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpINotEqual"}}, + {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGeU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpUGreaterThanEqual"}}, + {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGtU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpUGreaterThan"}}, + {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLeU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpULessThanEqual"}}, + {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLtU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpULessThan"}}, + {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLgU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpINotEqual"}}, {Recompile_VCndmaskB32_VdstVsrc0Vsrc1Smask2, ShaderInstructionType::VCndmaskB32, ShaderInstructionFormat::VdstVsrc0Vsrc1Smask2, {U""}}, @@ -5265,7 +5398,7 @@ void Spirv::WriteAnnotations() { for (uint32_t i = 0; i < m_ps_input_info->input_num; i++) { - vars.Add(String::FromPrintf("OpDecorate %%attr%d Location %d", i, i)); + vars.Add(String::FromPrintf("OpDecorate %%attr%d Location %d", i, m_ps_input_info->interpolator_settings[i])); } if (m_ps_input_info->ps_pos_xy) { @@ -6202,6 +6335,15 @@ String SpirvGetEmbeddedVs(uint32_t id) return EMBEDDED_SHADER_VS_0; } +String SpirvGetEmbeddedPs(uint32_t id) +{ + EXIT_NOT_IMPLEMENTED(id != 0); + + KYTY_NOT_IMPLEMENTED; + + return U""; +} + } // namespace Kyty::Libs::Graphics #endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Graphics/Tile.cpp b/source/emulator/src/Graphics/Tile.cpp index d8df660..ee4cc7e 100644 --- a/source/emulator/src/Graphics/Tile.cpp +++ b/source/emulator/src/Graphics/Tile.cpp @@ -614,6 +614,8 @@ void TileGetVideoOutSize(uint32_t width, uint32_t height, bool tile, bool neo, u void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile, bool neo, uint32_t* total_size, uint32_t* level_sizes, uint32_t* padded_width, uint32_t* padded_height) { + KYTY_PROFILER_FUNCTION(); + struct Padded { uint32_t width; @@ -661,6 +663,11 @@ void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t h { {512, 512}, {256, 256}, {128, 128}, {64, 64}, {32, 32}, {16, 16}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, } }, { 10, 0, 512, 512, 10, 13, true, {1048576, 262144, 65536, 16384, 4096, 1024, 256, 256, 256, 256, }, { {512, 512}, {256, 256}, {128, 128}, {64, 64}, {32, 32}, {16, 16}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, } }, + // kDataFormatB8G8R8A8Unorm, 512, 768, kTileModeThin_1dThin + { 10, 0, 512, 768, 10, 13, false, {1572864, 1048576, 131072, 32768, 8192, 2048, 512, 256, 256, 256, }, + { {512, 768}, {256, 512}, {128, 256}, {64, 128}, {32, 64}, {16, 32}, {8, 16}, {8, 8}, {8, 8}, {8, 8}, } }, + { 10, 0, 512, 768, 10, 13, true, {1572864, 1048576, 131072, 32768, 8192, 2048, 512, 256, 256, 256, }, + { {512, 768}, {256, 512}, {128, 256}, {64, 128}, {32, 64}, {16, 32}, {8, 16}, {8, 8}, {8, 8}, {8, 8}, } }, // kDataFormatB8G8R8A8Unorm, 256, 256, kTileModeThin_2dThin { 10, 0, 256, 256, 9, 14, false, {262144, 65536, 16384, 4096, 1024, 256, 256, 256, 256, }, { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, } }, diff --git a/source/emulator/src/Graphics/VideoOut.cpp b/source/emulator/src/Graphics/VideoOut.cpp index e0d0f63..7ec197a 100644 --- a/source/emulator/src/Graphics/VideoOut.cpp +++ b/source/emulator/src/Graphics/VideoOut.cpp @@ -846,7 +846,7 @@ KYTY_SYSV_ABI int VideoOutRegisterBuffers(int handle, int start_index, void* con ctx->buffers[i + start_index].buffer_size = buffer_size; ctx->buffers[i + start_index].buffer_pitch = buffer_pitch; ctx->buffers[i + start_index].buffer_vulkan = static_cast(Graphics::GpuMemoryCreateObject( - g_video_out_context->GetGraphicCtx(), reinterpret_cast(addresses[i]), buffer_size, vulkan_buffer_info)); + g_video_out_context->GetGraphicCtx(), nullptr, reinterpret_cast(addresses[i]), buffer_size, vulkan_buffer_info)); EXIT_NOT_IMPLEMENTED(ctx->buffers[i + start_index].buffer_vulkan == nullptr); diff --git a/source/emulator/src/Graphics/Window.cpp b/source/emulator/src/Graphics/Window.cpp index 36a3822..0862465 100644 --- a/source/emulator/src/Graphics/Window.cpp +++ b/source/emulator/src/Graphics/Window.cpp @@ -229,6 +229,8 @@ struct WindowContext SurfaceCapabilities* surface_capabilities = nullptr; GameApi* game = nullptr; + char device_name[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE] = {0}; + Core::Mutex mutex; bool graphic_initialized = false; Core::CondVar graphic_initialized_condvar; @@ -1376,57 +1378,57 @@ static VkPhysicalDevice VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceK if (!skip_device && !CheckFormat(device, VK_FORMAT_R8G8B8A8_SRGB, false, VK_FORMAT_FEATURE_BLIT_SRC_BIT)) { - printf("Format VK_FORMAT_R8G8B8A8_SRGB cannot be used as transfer source"); + printf("Format VK_FORMAT_R8G8B8A8_SRGB cannot be used as transfer source\n"); skip_device = true; } if (!skip_device && !CheckFormat(device, VK_FORMAT_D32_SFLOAT, true, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - printf("Format VK_FORMAT_D32_SFLOAT cannot be used as depth buffer"); + printf("Format VK_FORMAT_D32_SFLOAT cannot be used as depth buffer\n"); skip_device = true; } if (!skip_device && !CheckFormat(device, VK_FORMAT_D32_SFLOAT_S8_UINT, true, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - printf("Format VK_FORMAT_D32_SFLOAT_S8_UINT cannot be used as depth buffer"); + printf("Format VK_FORMAT_D32_SFLOAT_S8_UINT cannot be used as depth buffer\n"); skip_device = true; } if (!skip_device && !CheckFormat(device, VK_FORMAT_D16_UNORM, true, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - printf("Format VK_FORMAT_D16_UNORM cannot be used as depth buffer"); + printf("Format VK_FORMAT_D16_UNORM cannot be used as depth buffer\n"); skip_device = true; } if (!skip_device && !CheckFormat(device, VK_FORMAT_D24_UNORM_S8_UINT, true, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - printf("Format VK_FORMAT_D24_UNORM_S8_UINT cannot be used as depth buffer"); + printf("Format VK_FORMAT_D24_UNORM_S8_UINT cannot be used as depth buffer\n"); skip_device = true; } if (!skip_device && !CheckFormat(device, VK_FORMAT_BC3_SRGB_BLOCK, true, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) { - printf("Format VK_FORMAT_BC3_SRGB_BLOCK cannot be used as texture"); + printf("Format VK_FORMAT_BC3_SRGB_BLOCK cannot be used as texture\n"); skip_device = true; } if (!skip_device && !CheckFormat(device, VK_FORMAT_R8G8B8A8_SRGB, true, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) { - printf("Format VK_FORMAT_R8G8B8A8_SRGB cannot be used as texture"); + printf("Format VK_FORMAT_R8G8B8A8_SRGB cannot be used as texture\n"); skip_device = true; } if (!skip_device && !CheckFormat(device, VK_FORMAT_R8G8B8A8_SRGB, true, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) { - printf("Format VK_FORMAT_R8G8B8A8_SRGB cannot be used as texture"); + printf("Format VK_FORMAT_R8G8B8A8_SRGB cannot be used as texture\n"); if (!skip_device && !CheckFormat(device, VK_FORMAT_R8G8B8A8_UNORM, true, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) { - printf("Format VK_FORMAT_R8G8B8A8_UNORM cannot be used as texture"); + printf("Format VK_FORMAT_R8G8B8A8_UNORM cannot be used as texture\n"); skip_device = true; } } @@ -1434,12 +1436,12 @@ static VkPhysicalDevice VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceK if (!skip_device && !CheckFormat(device, VK_FORMAT_B8G8R8A8_SRGB, true, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) { - printf("Format VK_FORMAT_B8G8R8A8_SRGB cannot be used as texture"); + printf("Format VK_FORMAT_B8G8R8A8_SRGB cannot be used as texture\n"); if (!skip_device && !CheckFormat(device, VK_FORMAT_B8G8R8A8_UNORM, true, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) { - printf("Format VK_FORMAT_B8G8R8A8_UNORM cannot be used as texture"); + printf("Format VK_FORMAT_B8G8R8A8_UNORM cannot be used as texture\n"); skip_device = true; } } @@ -1982,6 +1984,13 @@ static void VulkanCreate(WindowContext* ctx) EXIT("Could not find suitable device"); } + VkPhysicalDeviceProperties device_properties {}; + vkGetPhysicalDeviceProperties(ctx->graphic_ctx.physical_device, &device_properties); + + printf("Select device: %s\n", device_properties.deviceName); + + memcpy(ctx->device_name, device_properties.deviceName, sizeof(ctx->device_name)); + ctx->graphic_ctx.device = VulkanCreateDevice(ctx->graphic_ctx.physical_device, ctx->surface, &r, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, GraphicContext::QUEUES_NUM, &ctx->graphic_ctx.queue_family_index, device_extensions); @@ -2074,7 +2083,8 @@ void WindowShowFps() EXIT_IF(g_window_ctx == nullptr); EXIT_IF(g_window_ctx->game == nullptr); - auto fps = String::FromPrintf("frame: %d, fps: %f", g_window_ctx->game->m_frame_num, g_window_ctx->game->m_current_fps); + auto fps = String::FromPrintf("[%s], frame: %d, fps: %f", g_window_ctx->device_name, g_window_ctx->game->m_frame_num, + g_window_ctx->game->m_current_fps); SDL_SetWindowTitle(g_window_ctx->window, fps.C_Str()); } diff --git a/source/emulator/src/Kernel/Memory.cpp b/source/emulator/src/Kernel/Memory.cpp index d10f96f..d822cfb 100644 --- a/source/emulator/src/Kernel/Memory.cpp +++ b/source/emulator/src/Kernel/Memory.cpp @@ -456,7 +456,7 @@ int KYTY_SYSV_ABI KernelMunmap(uint64_t vaddr, size_t len) if (gpu_mode != Graphics::GpuMemoryMode::NoAccess) { Graphics::GraphicsRunWait(); - Graphics::GpuMemoryFree(Graphics::WindowGetGraphicContext(), vaddr, len); + Graphics::GpuMemoryFree(Graphics::WindowGetGraphicContext(), vaddr, len, true); } return OK; @@ -575,7 +575,7 @@ int KYTY_SYSV_ABI KernelReleaseDirectMemory(int64_t start, size_t len) if (gpu_mode != Graphics::GpuMemoryMode::NoAccess) { Graphics::GraphicsRunWait(); - Graphics::GpuMemoryFree(Graphics::WindowGetGraphicContext(), vaddr, size); + Graphics::GpuMemoryFree(Graphics::WindowGetGraphicContext(), vaddr, size, true); } return OK; diff --git a/source/emulator/src/RuntimeLinker.cpp b/source/emulator/src/RuntimeLinker.cpp index be75361..33cbade 100644 --- a/source/emulator/src/RuntimeLinker.cpp +++ b/source/emulator/src/RuntimeLinker.cpp @@ -10,6 +10,7 @@ #include "Kyty/Sys/SysDbg.h" #include "Emulator/Elf.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #include "Emulator/Jit.h" #include "Emulator/Kernel/Pthread.h" #include "Emulator/Profiler.h" @@ -152,10 +153,18 @@ static VirtualMemory::Mode get_mode(Elf64_Word flags) } } -static void dbg_exception_handler(const VirtualMemory::ExceptionHandler::ExceptionInfo* info) +static void kyty_exception_handler(const VirtualMemory::ExceptionHandler::ExceptionInfo* info) { + printf("kyty_exception_handler: %016" PRIx64 "\n", info->exception_address); + if (info->type == VirtualMemory::ExceptionHandler::ExceptionType::AccessViolation) { + if (info->access_violation_type == VirtualMemory::ExceptionHandler::AccessViolationType::Write && + Libs::Graphics::GpuMemoryCheckAccessViolation(info->access_violation_vaddr, sizeof(uint64_t))) + { + return; + } + EXIT("Access violation: %s [%016" PRIx64 "] %s\n", Core::EnumName(info->access_violation_type).C_Str(), info->access_violation_vaddr, (info->access_violation_vaddr == INVALID_MEMORY ? "(Unpatched object)" : "")); } @@ -1041,12 +1050,14 @@ void RuntimeLinker::LoadProgramToMemory(Program* program) if (is_shared) { program->exception_handler->Install(program->base_vaddr, program->base_vaddr + program->base_size_aligned, - program->base_size_aligned + exception_handler_size + tls_handler_size, dbg_exception_handler); + program->base_size_aligned + exception_handler_size + tls_handler_size, kyty_exception_handler); } else { program->exception_handler->Install(0, program->base_vaddr + program->base_size_aligned, program->base_vaddr + program->base_size_aligned + exception_handler_size + tls_handler_size, - dbg_exception_handler); + kyty_exception_handler); + + VirtualMemory::ExceptionHandler::InstallVectored(kyty_exception_handler); } // program->elf->SetBaseVAddr(program->base_vaddr); diff --git a/source/emulator/src/VirtualMemory.cpp b/source/emulator/src/VirtualMemory.cpp index b4961f2..a4fee1a 100644 --- a/source/emulator/src/VirtualMemory.cpp +++ b/source/emulator/src/VirtualMemory.cpp @@ -89,6 +89,8 @@ public: { ExceptionHandler::ExceptionInfo info {}; + info.exception_address = reinterpret_cast(exception_record->ExceptionAddress); + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { info.type = ExceptionHandler::ExceptionType::AccessViolation; @@ -140,8 +142,12 @@ public: PRUNTIME_FUNCTION function_table = nullptr; ExceptionHandler::handler_func_t func = nullptr; + + static ExceptionHandler::handler_func_t g_vec_func; }; +ExceptionHandler::handler_func_t ExceptionHandlerPrivate::g_vec_func = nullptr; + ExceptionHandler::ExceptionHandler(): m_p(new ExceptionHandlerPrivate) {} ExceptionHandler::~ExceptionHandler() @@ -178,6 +184,49 @@ bool ExceptionHandler::Install(uint64_t base_address, uint64_t handler_addr, uin return false; } +static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception) +{ + PEXCEPTION_RECORD exception_record = exception->ExceptionRecord; + + ExceptionHandler::ExceptionInfo info {}; + + info.exception_address = reinterpret_cast(exception_record->ExceptionAddress); + + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + { + info.type = ExceptionHandler::ExceptionType::AccessViolation; + switch (exception_record->ExceptionInformation[0]) + { + case 0: info.access_violation_type = ExceptionHandler::AccessViolationType::Read; break; + case 1: info.access_violation_type = ExceptionHandler::AccessViolationType::Write; break; + case 8: info.access_violation_type = ExceptionHandler::AccessViolationType::Execute; break; + default: info.access_violation_type = ExceptionHandler::AccessViolationType::Unknown; break; + } + info.access_violation_vaddr = exception_record->ExceptionInformation[1]; + } + + ExceptionHandlerPrivate::g_vec_func(&info); + + return EXCEPTION_CONTINUE_EXECUTION; +} + +bool ExceptionHandler::InstallVectored(handler_func_t func) +{ + if (ExceptionHandlerPrivate::g_vec_func == nullptr) + { + ExceptionHandlerPrivate::g_vec_func = func; + + if (AddVectoredExceptionHandler(1, ExceptionFilter) == nullptr) + { + printf("AddVectoredExceptionHandler() failed\n"); + return false; + } + + return true; + } + return false; +} + bool ExceptionHandler::Uninstall() { if (m_p->function_table != nullptr) @@ -291,6 +340,8 @@ bool Free(uint64_t address) bool Protect(uint64_t address, uint64_t size, Mode mode, Mode* old_mode) { + KYTY_PROFILER_FUNCTION(); + DWORD old_protect = 0; if (VirtualProtect(reinterpret_cast(static_cast(address)), size, get_protection_flag(mode), &old_protect) == 0) {