From 02a77aa81a666db3a77609dc5f991890b5027dfc Mon Sep 17 00:00:00 2001 From: InoriRus Date: Sun, 20 Feb 2022 20:04:12 +1000 Subject: [PATCH] render to mips --- appveyor.yml | 2 +- source/CMakeLists.txt | 2 +- .../Emulator/Graphics/GraphicContext.h | 4 + .../Emulator/Graphics/GraphicsRender.h | 2 + .../Graphics/Objects/DepthStencilBuffer.h | 14 +- .../Emulator/Graphics/Objects/GpuMemory.h | 24 +- .../Emulator/Graphics/Objects/IndexBuffer.h | 14 +- .../include/Emulator/Graphics/Objects/Label.h | 13 +- .../Emulator/Graphics/Objects/RenderTexture.h | 14 +- .../Emulator/Graphics/Objects/StorageBuffer.h | 14 +- .../Graphics/Objects/StorageTexture.h | 51 +++ .../Emulator/Graphics/Objects/Texture.h | 29 +- .../Emulator/Graphics/Objects/VertexBuffer.h | 14 +- .../Graphics/Objects/VideoOutBuffer.h | 14 +- .../include/Emulator/Graphics/Shader.h | 20 +- .../include/Emulator/Graphics/Utils.h | 56 ++- .../emulator/src/Graphics/GraphicsRender.cpp | 184 +++++---- source/emulator/src/Graphics/GraphicsRun.cpp | 2 + .../Graphics/Objects/DepthStencilBuffer.cpp | 41 +- .../src/Graphics/Objects/GpuMemory.cpp | 105 +++-- .../src/Graphics/Objects/IndexBuffer.cpp | 18 +- .../emulator/src/Graphics/Objects/Label.cpp | 40 +- .../src/Graphics/Objects/RenderTexture.cpp | 134 +++--- .../src/Graphics/Objects/StorageBuffer.cpp | 59 +-- .../src/Graphics/Objects/StorageTexture.cpp | 358 ++++++++++++++++ .../emulator/src/Graphics/Objects/Texture.cpp | 391 +++++++++++++----- .../src/Graphics/Objects/VertexBuffer.cpp | 19 +- .../src/Graphics/Objects/VideoOutBuffer.cpp | 130 +++--- source/emulator/src/Graphics/Shader.cpp | 300 +++++++++----- source/emulator/src/Graphics/ShaderSpirv.cpp | 290 ++++++++++--- source/emulator/src/Graphics/Tile.cpp | 14 +- source/emulator/src/Graphics/Utils.cpp | 100 ++++- source/emulator/src/Graphics/Window.cpp | 11 +- 33 files changed, 1827 insertions(+), 656 deletions(-) create mode 100644 source/emulator/include/Emulator/Graphics/Objects/StorageTexture.h create mode 100644 source/emulator/src/Graphics/Objects/StorageTexture.cpp diff --git a/appveyor.yml b/appveyor.yml index 9a5f913..df9a705 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.0.9.build-{build} +version: 0.0.10.build-{build} image: Visual Studio 2019 environment: matrix: diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index bf42e1f..061dda7 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.9) +project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.10) include(src_script.cmake) diff --git a/source/emulator/include/Emulator/Graphics/GraphicContext.h b/source/emulator/include/Emulator/Graphics/GraphicContext.h index ce042e9..62f0ee1 100644 --- a/source/emulator/include/Emulator/Graphics/GraphicContext.h +++ b/source/emulator/include/Emulator/Graphics/GraphicContext.h @@ -87,6 +87,10 @@ struct TextureVulkanImage: public VulkanImage { }; +struct StorageTextureVulkanImage: public VulkanImage +{ +}; + struct RenderTextureVulkanImage: public VulkanImage { }; diff --git a/source/emulator/include/Emulator/Graphics/GraphicsRender.h b/source/emulator/include/Emulator/Graphics/GraphicsRender.h index 7bc18a3..9e5d03e 100644 --- a/source/emulator/include/Emulator/Graphics/GraphicsRender.h +++ b/source/emulator/include/Emulator/Graphics/GraphicsRender.h @@ -16,6 +16,7 @@ class CommandProcessor; struct VideoOutVulkanImage; struct DepthStencilVulkanImage; struct TextureVulkanImage; +struct StorageTextureVulkanImage; struct RenderTextureVulkanImage; struct VulkanCommandPool; struct VulkanBuffer; @@ -90,6 +91,7 @@ void DeleteFramebuffer(DepthStencilVulkanImage* image); void DeleteFramebuffer(RenderTextureVulkanImage* image); void DeleteDescriptor(VulkanBuffer* buffer); void DeleteDescriptor(TextureVulkanImage* image); +void DeleteDescriptor(StorageTextureVulkanImage* image); void DeleteDescriptor(RenderTextureVulkanImage* image); int GraphicsRenderAddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata); diff --git a/source/emulator/include/Emulator/Graphics/Objects/DepthStencilBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/DepthStencilBuffer.h index 152b3e8..8f7f854 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/DepthStencilBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/DepthStencilBuffer.h @@ -10,9 +10,6 @@ namespace Kyty::Libs::Graphics { -struct GraphicContext; -struct VulkanMemory; - class DepthStencilBufferObject: public GpuObject { public: @@ -33,12 +30,13 @@ public: type = Graphics::GpuMemoryObjectType::DepthStencilBuffer; } - void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override; - bool Equal(const uint64_t* other) const override; + bool Equal(const uint64_t* other) 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; + [[nodiscard]] create_func_t GetCreateFunc() const override; + [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override { return nullptr; }; + [[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; }; + [[nodiscard]] delete_func_t GetDeleteFunc() const override; + [[nodiscard]] update_func_t GetUpdateFunc() const override; }; } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h b/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h index e200f2a..9c34868 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h +++ b/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h @@ -34,6 +34,7 @@ enum class GpuMemoryObjectType : uint64_t StorageBuffer, Texture, RenderTexture, + StorageTexture, Max }; @@ -47,10 +48,14 @@ struct GpuMemoryObject class GpuObject { public: - 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, - int vaddr_num); + 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 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, + int vaddr_num); static constexpr int PARAMS_MAX = 8; @@ -59,12 +64,13 @@ public: KYTY_CLASS_DEFAULT_COPY(GpuObject); - virtual void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const = 0; - virtual bool Equal(const uint64_t* other) const = 0; + virtual bool Equal(const uint64_t* other) const = 0; - [[nodiscard]] virtual write_back_func_t GetWriteBackFunc() const = 0; - [[nodiscard]] virtual delete_func_t GetDeleteFunc() const = 0; - [[nodiscard]] virtual update_func_t GetUpdateFunc() const = 0; + [[nodiscard]] virtual create_func_t GetCreateFunc() const = 0; + [[nodiscard]] virtual create_from_objects_func_t GetCreateFromObjectsFunc() const = 0; + [[nodiscard]] virtual write_back_func_t GetWriteBackFunc() const = 0; + [[nodiscard]] virtual delete_func_t GetDeleteFunc() const = 0; + [[nodiscard]] virtual update_func_t GetUpdateFunc() const = 0; uint64_t params[PARAMS_MAX] = {}; bool check_hash = false; diff --git a/source/emulator/include/Emulator/Graphics/Objects/IndexBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/IndexBuffer.h index df7dfd7..203258d 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/IndexBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/IndexBuffer.h @@ -10,9 +10,6 @@ namespace Kyty::Libs::Graphics { -struct GraphicContext; -struct VulkanMemory; - class IndexBufferGpuObject: public GpuObject { public: @@ -22,12 +19,13 @@ public: type = Graphics::GpuMemoryObjectType::IndexBuffer; } - void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override; - bool Equal(const uint64_t* other) const override; + bool Equal(const uint64_t* other) 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; + [[nodiscard]] create_func_t GetCreateFunc() const override; + [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override { return nullptr; }; + [[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; }; + [[nodiscard]] delete_func_t GetDeleteFunc() const override; + [[nodiscard]] update_func_t GetUpdateFunc() const override; }; } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/Graphics/Objects/Label.h b/source/emulator/include/Emulator/Graphics/Objects/Label.h index 848ec9e..a7b3038 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/Label.h +++ b/source/emulator/include/Emulator/Graphics/Objects/Label.h @@ -11,9 +11,7 @@ namespace Kyty::Libs::Graphics { struct Label; -struct GraphicContext; class CommandBuffer; -struct VulkanMemory; void LabelInit(); @@ -46,12 +44,13 @@ public: type = Graphics::GpuMemoryObjectType::Label; } - void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override; - bool Equal(const uint64_t* other) const override; + bool Equal(const uint64_t* other) 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; + [[nodiscard]] create_func_t GetCreateFunc() const override; + [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override { return nullptr; }; + [[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; }; + [[nodiscard]] delete_func_t GetDeleteFunc() const override; + [[nodiscard]] update_func_t GetUpdateFunc() const override; }; void LabelSet(CommandBuffer* buffer, Label* label); diff --git a/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h b/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h index 4a283d4..6852a6a 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h +++ b/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h @@ -10,9 +10,6 @@ namespace Kyty::Libs::Graphics { -struct GraphicContext; -struct VulkanMemory; - enum class RenderTextureFormat : uint64_t { R8G8B8A8Unorm @@ -40,12 +37,13 @@ public: type = Graphics::GpuMemoryObjectType::RenderTexture; } - void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override; - bool Equal(const uint64_t* other) const override; + bool Equal(const uint64_t* other) 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; + [[nodiscard]] create_func_t GetCreateFunc() const override; + [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override { return nullptr; }; + [[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; }; + [[nodiscard]] delete_func_t GetDeleteFunc() const override; + [[nodiscard]] update_func_t GetUpdateFunc() const override; }; } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h index 9656023..90d2f5a 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h @@ -10,9 +10,6 @@ namespace Kyty::Libs::Graphics { -struct GraphicContext; -struct VulkanMemory; - class StorageBufferGpuObject: public GpuObject { public: @@ -25,12 +22,13 @@ public: type = Graphics::GpuMemoryObjectType::StorageBuffer; } - void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override; - bool Equal(const uint64_t* other) const override; + bool Equal(const uint64_t* other) const override; - [[nodiscard]] write_back_func_t GetWriteBackFunc() const override; - [[nodiscard]] delete_func_t GetDeleteFunc() const override; - [[nodiscard]] update_func_t GetUpdateFunc() const override; + [[nodiscard]] create_func_t GetCreateFunc() const override; + [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override { return nullptr; }; + [[nodiscard]] write_back_func_t GetWriteBackFunc() const override; + [[nodiscard]] delete_func_t GetDeleteFunc() const override; + [[nodiscard]] update_func_t GetUpdateFunc() const override; }; } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/Graphics/Objects/StorageTexture.h b/source/emulator/include/Emulator/Graphics/Objects/StorageTexture.h new file mode 100644 index 0000000..997af89 --- /dev/null +++ b/source/emulator/include/Emulator/Graphics/Objects/StorageTexture.h @@ -0,0 +1,51 @@ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_STORAGETEXTURE_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_STORAGETEXTURE_H_ + +#include "Kyty/Core/Common.h" + +#include "Emulator/Common.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" + +#ifdef KYTY_EMU_ENABLED + +namespace Kyty::Libs::Graphics { + +class StorageTextureObject: public GpuObject +{ +public: + static constexpr int PARAM_DFMT_NFMT = 0; + static constexpr int PARAM_PITCH = 1; + static constexpr int PARAM_WIDTH_HEIGHT = 2; + static constexpr int PARAM_LEVELS = 3; + static constexpr int PARAM_TILE = 4; + 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) + { + 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_TILE] = tile; + params[PARAM_NEO] = neo ? 1 : 0; + params[PARAM_SWIZZLE] = swizzle; + check_hash = true; + type = Graphics::GpuMemoryObjectType::StorageTexture; + } + + 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]] write_back_func_t GetWriteBackFunc() const override { return nullptr; }; + [[nodiscard]] delete_func_t GetDeleteFunc() const override; + [[nodiscard]] update_func_t GetUpdateFunc() const override; +}; + +} // namespace Kyty::Libs::Graphics + +#endif // KYTY_EMU_ENABLED + +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_STORAGETEXTURE_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/Objects/Texture.h b/source/emulator/include/Emulator/Graphics/Objects/Texture.h index 31b2c55..989392e 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/Texture.h +++ b/source/emulator/include/Emulator/Graphics/Objects/Texture.h @@ -10,31 +10,23 @@ namespace Kyty::Libs::Graphics { -struct GraphicContext; -struct VulkanMemory; - class TextureObject: public GpuObject { public: - static constexpr int TEXTURE_USAGE_SAMPLED = 0; - static constexpr int TEXTURE_USAGE_STORAGE = 1; - static constexpr int PARAM_DFMT_NFMT = 0; static constexpr int PARAM_PITCH = 1; static constexpr int PARAM_WIDTH_HEIGHT = 2; - static constexpr int PARAM_USAGE = 3; - static constexpr int PARAM_LEVELS = 4; - static constexpr int PARAM_TILE = 5; - static constexpr int PARAM_NEO = 6; - static constexpr int PARAM_SWIZZLE = 7; + static constexpr int PARAM_LEVELS = 3; + static constexpr int PARAM_TILE = 4; + 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, uint32_t usage) + 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_USAGE] = usage; params[PARAM_LEVELS] = levels; params[PARAM_TILE] = tile; params[PARAM_NEO] = neo ? 1 : 0; @@ -43,12 +35,13 @@ public: type = Graphics::GpuMemoryObjectType::Texture; } - void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override; - bool Equal(const uint64_t* other) const override; + bool Equal(const uint64_t* other) 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; + [[nodiscard]] create_func_t GetCreateFunc() const override; + [[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; }; } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/Graphics/Objects/VertexBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/VertexBuffer.h index 81f0da5..1040516 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/VertexBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/VertexBuffer.h @@ -10,9 +10,6 @@ namespace Kyty::Libs::Graphics { -struct GraphicContext; -struct VulkanMemory; - class VertexBufferGpuObject: public GpuObject { public: @@ -22,12 +19,13 @@ public: type = Graphics::GpuMemoryObjectType::VertexBuffer; } - void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override; - bool Equal(const uint64_t* other) const override; + bool Equal(const uint64_t* other) 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; + [[nodiscard]] create_func_t GetCreateFunc() const override; + [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override { return nullptr; }; + [[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; }; + [[nodiscard]] delete_func_t GetDeleteFunc() const override; + [[nodiscard]] update_func_t GetUpdateFunc() const override; }; } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/Graphics/Objects/VideoOutBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/VideoOutBuffer.h index e678037..2bf36e8 100644 --- a/source/emulator/include/Emulator/Graphics/Objects/VideoOutBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/VideoOutBuffer.h @@ -10,9 +10,6 @@ namespace Kyty::Libs::Graphics { -struct GraphicContext; -struct VulkanMemory; - class VideoOutBufferObject: public GpuObject { public: @@ -35,12 +32,13 @@ public: type = Graphics::GpuMemoryObjectType::VideoOutBuffer; } - void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override; - bool Equal(const uint64_t* other) const override; + bool Equal(const uint64_t* other) 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; + [[nodiscard]] create_func_t GetCreateFunc() const override; + [[nodiscard]] create_from_objects_func_t GetCreateFromObjectsFunc() const override { return nullptr; }; + [[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; }; + [[nodiscard]] delete_func_t GetDeleteFunc() const override; + [[nodiscard]] update_func_t GetUpdateFunc() const override; }; } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/Graphics/Shader.h b/source/emulator/include/Emulator/Graphics/Shader.h index 64ef63a..966c6c5 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, + ImageStoreMip, SAddcU32, SAddI32, SAddU32, @@ -284,6 +285,7 @@ enum Format : uint64_t Vdata3Vaddr3StSsDmask7 = FormatDefine({DA3, S0A3, S1A8, S2A4, Dmask7}), Vdata4Vaddr3StSsDmaskF = FormatDefine({DA4, S0A3, S1A8, S2A4, DmaskF}), Vdata4Vaddr3StDmaskF = FormatDefine({DA4, S0A3, S1A8, DmaskF}), + Vdata4Vaddr4StDmaskF = FormatDefine({DA4, S0A4, S1A8, DmaskF}), VdstVsrc0Vsrc1Smask2 = FormatDefine({D, S0, S1, S2A2}), VdstVsrc0Vsrc1Vsrc2 = FormatDefine({D, S0, S1, S2}), VdstVsrcAttrChan = FormatDefine({D, S0, Attr}), @@ -570,6 +572,13 @@ enum class ShaderStorageUsage ReadWrite, }; +enum class ShaderTextureUsage +{ + Unknown, + ReadOnly, + ReadWrite, +}; + struct ShaderStorageResources { static constexpr int BUFFERS_MAX = 16; @@ -588,11 +597,13 @@ struct ShaderTextureResources static constexpr int RES_MAX = 16; ShaderTextureResource textures[RES_MAX]; + ShaderTextureUsage usages[RES_MAX] = {}; int slots[RES_MAX] = {0}; int start_register[RES_MAX] = {0}; bool extended[RES_MAX] = {}; int textures_num = 0; - int binding_index = 0; + int binding_sampled_index = 0; + int binding_storage_index = 0; }; struct ShaderSamplerResources @@ -641,7 +652,9 @@ struct ShaderBindResources struct ShaderBindParameters { - bool textures2D_without_sampler = false; + bool textures2d_without_sampler[ShaderTextureResources::RES_MAX] = {}; + int textures2d_sampled_num = 0; + int textures2d_storage_num = 0; }; struct ShaderVertexInputInfo @@ -674,9 +687,12 @@ struct ShaderPixelInputInfo uint8_t target_output_mode[8] = {}; bool ps_pos_xy = false; bool ps_pixel_kill_enable = false; + bool ps_early_z = false; + bool ps_execute_on_noop = false; ShaderBindResources bind; }; +void ShaderCalcBindingIndices(ShaderBindResources* bind); void ShaderGetInputInfoVS(const VertexShaderInfo* regs, ShaderVertexInputInfo* info); void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputInfo* vs_info, ShaderPixelInputInfo* ps_info); void ShaderGetInputInfoCS(const ComputeShaderInfo* regs, ShaderComputeInputInfo* info); diff --git a/source/emulator/include/Emulator/Graphics/Utils.h b/source/emulator/include/Emulator/Graphics/Utils.h index c9be651..4aaea47 100644 --- a/source/emulator/include/Emulator/Graphics/Utils.h +++ b/source/emulator/include/Emulator/Graphics/Utils.h @@ -5,6 +5,8 @@ #include "Emulator/Common.h" +#include + #ifdef KYTY_EMU_ENABLED namespace Kyty { @@ -18,25 +20,42 @@ class CommandBuffer; struct GraphicContext; struct VulkanBuffer; struct VulkanImage; -struct TextureVulkanImage; struct DepthStencilVulkanImage; struct VulkanSwapchain; struct BufferImageCopy { uint32_t offset; + uint32_t pitch; + uint32_t dst_level; uint32_t width; uint32_t height; - uint32_t pitch; + int dst_x; + int dst_y; +}; + +struct ImageImageCopy +{ + VulkanImage* src_image; + uint32_t src_level; + uint32_t dst_level; + uint32_t width; + uint32_t height; + int src_x; + int src_y; + int dst_x; + int dst_y; }; void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, uint32_t src_pitch, VulkanImage* dst_image); -void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, TextureVulkanImage* dst_image, - const Vector& regions, uint64_t dst_layout); +void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, VulkanImage* dst_image, const Vector& regions, + uint64_t dst_layout); +void UtilImageToImage(CommandBuffer* buffer, const Vector& regions, VulkanImage* dst_image, uint64_t dst_layout); void UtilBlitImage(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchain* dst_swapchain); void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, uint32_t src_pitch); -void UtilFillImage(GraphicContext* ctx, TextureVulkanImage* dst_image, const void* src_data, uint64_t size, - const Vector& regions, uint64_t dst_layout); +void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, const Vector& regions, + uint64_t dst_layout); +void UtilFillImage(GraphicContext* ctx, const Vector& regions, VulkanImage* dst_image, uint64_t dst_layout); void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size); void UtilSetDepthLayoutOptimal(DepthStencilVulkanImage* image); void UtilSetImageLayoutOptimal(VulkanImage* image); @@ -44,6 +63,31 @@ void UtilSetImageLayoutOptimal(VulkanImage* image); void VulkanCreateBuffer(GraphicContext* gctx, uint64_t size, VulkanBuffer* buffer); void VulkanDeleteBuffer(GraphicContext* gctx, VulkanBuffer* buffer); +inline std::pair UtilCalcMipmapOffset(uint32_t lod, uint32_t width, uint32_t height) +{ + uint32_t mip_width = width; + uint32_t mip_height = height; + int mip_x = 0; + int mip_y = 0; + + for (uint32_t i = 0; i < 16; i++) + { + if (i == lod) + { + return {mip_x, mip_y}; + } + + bool odd = ((i & 1u) != 0); + mip_x += static_cast(odd ? mip_width : 0); + mip_y += static_cast(odd ? 0 : mip_height); + + mip_width >>= (mip_width > 1 ? 1u : 0u); + mip_height >>= (mip_height > 1 ? 1u : 0u); + } + + return {mip_x, mip_y}; +} + } // namespace Kyty::Libs::Graphics #endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Graphics/GraphicsRender.cpp b/source/emulator/src/Graphics/GraphicsRender.cpp index ec3f58e..f18828f 100644 --- a/source/emulator/src/Graphics/GraphicsRender.cpp +++ b/source/emulator/src/Graphics/GraphicsRender.cpp @@ -14,6 +14,7 @@ #include "Emulator/Graphics/Objects/Label.h" #include "Emulator/Graphics/Objects/RenderTexture.h" #include "Emulator/Graphics/Objects/StorageBuffer.h" +#include "Emulator/Graphics/Objects/StorageTexture.h" #include "Emulator/Graphics/Objects/Texture.h" #include "Emulator/Graphics/Objects/VertexBuffer.h" #include "Emulator/Graphics/Objects/VideoOutBuffer.h" @@ -161,16 +162,15 @@ public: virtual ~DescriptorCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(DescriptorCache); - VkDescriptorSetLayout GetDescriptorSetLayout(Stage stage, int storage_buffers_num, int textures2d_sampled_num, - int textures2d_storage_num, int samplers_num, int gds_buffers_num); + VkDescriptorSetLayout GetDescriptorSetLayout(Stage stage, const ShaderBindResources& bind, const ShaderBindParameters& bind_params); VulkanDescriptorSet* Allocate(Stage stage, int storage_buffers_num, int textures2d_sampled_num, int textures2d_storage_num, int samplers_num, int gds_buffers_num); void Free(VulkanDescriptorSet* set); - VulkanDescriptorSet* GetDescriptor(Stage stage, int storage_buffers_num, VulkanBuffer** storage_buffers, int textures2d_sampled_num, - VulkanImage** textures2d_sampled, int textures2d_storage_num, VulkanImage** textures2d_storage, - int samplers_num, uint64_t* samplers, int gds_buffers_num, VulkanBuffer** gds_buffers); + VulkanDescriptorSet* GetDescriptor(Stage stage, VulkanBuffer** storage_buffers, VulkanImage** textures2d_sampled, + VulkanImage** textures2d_storage, uint64_t* samplers, VulkanBuffer** gds_buffers, + const ShaderBindResources& bind, const ShaderBindParameters& bind_params); void FreeDescriptor(VulkanBuffer* buffer); void FreeDescriptor(VulkanImage* image); @@ -1603,10 +1603,7 @@ static void CreateLayout(VkDescriptorSetLayout* set_layouts, uint32_t* set_layou { EXIT_IF(bind.descriptor_set_slot != *set_layouts_num); - set_layouts[*set_layouts_num] = g_render_ctx->GetDescriptorCache()->GetDescriptorSetLayout( - stage, bind.storage_buffers.buffers_num, (bind_params.textures2D_without_sampler ? 0 : bind.textures2D.textures_num), - (bind_params.textures2D_without_sampler ? bind.textures2D.textures_num : 0), bind.samplers.samplers_num, - (bind.gds_pointers.pointers_num > 0 ? 1 : 0)); + set_layouts[*set_layouts_num] = g_render_ctx->GetDescriptorCache()->GetDescriptorSetLayout(stage, bind, bind_params); (*set_layouts_num)++; } } @@ -2040,6 +2037,8 @@ VulkanPipeline* PipelineCache::CreatePipeline(VulkanFramebuffer* framebuffer, Re p.vs_shader_id = vs_id; p.params = new PipelineParameters; + 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; @@ -2241,12 +2240,22 @@ static void create_layout(GraphicContext* gctx, int storage_buffers_num, int tex { uint32_t binding_num = 0; - VkDescriptorSetLayoutBinding ubo_layout_binding[5] = {}; + ShaderBindResources tmp {}; + tmp.storage_buffers.buffers_num = storage_buffers_num; + tmp.textures2D.textures_num = textures2d_sampled_num + textures2d_storage_num; + tmp.samplers.samplers_num = samplers_num; + tmp.gds_pointers.pointers_num = gds_buffers_num; + + ShaderCalcBindingIndices(&tmp); + + constexpr uint32_t B_MAX = 5; + + VkDescriptorSetLayoutBinding ubo_layout_binding[B_MAX] = {}; if (storage_buffers_num > 0) { - EXIT_IF(binding_num >= sizeof(ubo_layout_binding) / sizeof(ubo_layout_binding[0])); - ubo_layout_binding[binding_num].binding = binding_num; + EXIT_IF(binding_num >= B_MAX); + ubo_layout_binding[binding_num].binding = tmp.storage_buffers.binding_index; ubo_layout_binding[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; ubo_layout_binding[binding_num].descriptorCount = storage_buffers_num; ubo_layout_binding[binding_num].stageFlags = stage; @@ -2256,8 +2265,8 @@ static void create_layout(GraphicContext* gctx, int storage_buffers_num, int tex if (textures2d_sampled_num > 0) { - EXIT_IF(binding_num >= sizeof(ubo_layout_binding) / sizeof(ubo_layout_binding[0])); - ubo_layout_binding[binding_num].binding = binding_num; + EXIT_IF(binding_num >= B_MAX); + ubo_layout_binding[binding_num].binding = tmp.textures2D.binding_sampled_index; ubo_layout_binding[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; ubo_layout_binding[binding_num].descriptorCount = textures2d_sampled_num; ubo_layout_binding[binding_num].stageFlags = stage; @@ -2267,8 +2276,8 @@ static void create_layout(GraphicContext* gctx, int storage_buffers_num, int tex if (textures2d_storage_num > 0) { - EXIT_IF(binding_num >= sizeof(ubo_layout_binding) / sizeof(ubo_layout_binding[0])); - ubo_layout_binding[binding_num].binding = binding_num; + EXIT_IF(binding_num >= B_MAX); + ubo_layout_binding[binding_num].binding = tmp.textures2D.binding_storage_index; ubo_layout_binding[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; ubo_layout_binding[binding_num].descriptorCount = textures2d_storage_num; ubo_layout_binding[binding_num].stageFlags = stage; @@ -2278,8 +2287,8 @@ static void create_layout(GraphicContext* gctx, int storage_buffers_num, int tex if (samplers_num > 0) { - EXIT_IF(binding_num >= sizeof(ubo_layout_binding) / sizeof(ubo_layout_binding[0])); - ubo_layout_binding[binding_num].binding = binding_num; + EXIT_IF(binding_num >= B_MAX); + ubo_layout_binding[binding_num].binding = tmp.samplers.binding_index; ubo_layout_binding[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; ubo_layout_binding[binding_num].descriptorCount = samplers_num; ubo_layout_binding[binding_num].stageFlags = stage; @@ -2289,8 +2298,8 @@ static void create_layout(GraphicContext* gctx, int storage_buffers_num, int tex if (gds_buffers_num > 0) { - EXIT_IF(binding_num >= sizeof(ubo_layout_binding) / sizeof(ubo_layout_binding[0])); - ubo_layout_binding[binding_num].binding = binding_num; + EXIT_IF(binding_num >= B_MAX); + ubo_layout_binding[binding_num].binding = tmp.gds_pointers.binding_index; ubo_layout_binding[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; ubo_layout_binding[binding_num].descriptorCount = gds_buffers_num; ubo_layout_binding[binding_num].stageFlags = stage; @@ -2472,11 +2481,16 @@ void DescriptorCache::Free(VulkanDescriptorSet* set) } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, int storage_buffers_num, VulkanBuffer** storage_buffers, - int textures2d_sampled_num, VulkanImage** textures2d_sampled, - int textures2d_storage_num, VulkanImage** textures2d_storage, int samplers_num, - uint64_t* samplers, int gds_buffers_num, VulkanBuffer** gds_buffers) +VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, VulkanBuffer** storage_buffers, VulkanImage** textures2d_sampled, + VulkanImage** textures2d_storage, uint64_t* samplers, VulkanBuffer** gds_buffers, + const ShaderBindResources& bind, const ShaderBindParameters& bind_params) { + 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; + int samplers_num = bind.samplers.samplers_num; + int gds_buffers_num = bind.gds_pointers.pointers_num; + EXIT_IF(storage_buffers_num < 0 || storage_buffers_num > BUFFERS_MAX); EXIT_IF(textures2d_sampled_num < 0 || textures2d_sampled_num > TEXTURES_SAMPLED_MAX); EXIT_IF(textures2d_storage_num < 0 || textures2d_storage_num > TEXTURES_STORAGE_MAX); @@ -2599,15 +2613,17 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, int storage_buf int binding_num = 0; - VkWriteDescriptorSet descriptor_write[5] = {}; + constexpr uint32_t B_MAX = 5; + + VkWriteDescriptorSet descriptor_write[B_MAX] = {}; if (storage_buffers_num > 0) { - EXIT_IF(binding_num >= static_cast(sizeof(descriptor_write) / sizeof(descriptor_write[0]))); + EXIT_IF(binding_num >= B_MAX); descriptor_write[binding_num].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write[binding_num].pNext = nullptr; descriptor_write[binding_num].dstSet = new_set->set; - descriptor_write[binding_num].dstBinding = binding_num; + descriptor_write[binding_num].dstBinding = bind.storage_buffers.binding_index; descriptor_write[binding_num].dstArrayElement = 0; descriptor_write[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; descriptor_write[binding_num].descriptorCount = storage_buffers_num; @@ -2619,11 +2635,11 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, int storage_buf if (textures2d_sampled_num > 0) { - EXIT_IF(binding_num >= static_cast(sizeof(descriptor_write) / sizeof(descriptor_write[0]))); + EXIT_IF(binding_num >= B_MAX); descriptor_write[binding_num].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write[binding_num].pNext = nullptr; descriptor_write[binding_num].dstSet = new_set->set; - descriptor_write[binding_num].dstBinding = binding_num; + descriptor_write[binding_num].dstBinding = bind.textures2D.binding_sampled_index; descriptor_write[binding_num].dstArrayElement = 0; descriptor_write[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; descriptor_write[binding_num].descriptorCount = textures2d_sampled_num; @@ -2635,11 +2651,11 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, int storage_buf if (textures2d_storage_num > 0) { - EXIT_IF(binding_num >= static_cast(sizeof(descriptor_write) / sizeof(descriptor_write[0]))); + EXIT_IF(binding_num >= B_MAX); descriptor_write[binding_num].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write[binding_num].pNext = nullptr; descriptor_write[binding_num].dstSet = new_set->set; - descriptor_write[binding_num].dstBinding = binding_num; + descriptor_write[binding_num].dstBinding = bind.textures2D.binding_storage_index; descriptor_write[binding_num].dstArrayElement = 0; descriptor_write[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; descriptor_write[binding_num].descriptorCount = textures2d_storage_num; @@ -2651,11 +2667,11 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, int storage_buf if (samplers_num > 0) { - EXIT_IF(binding_num >= static_cast(sizeof(descriptor_write) / sizeof(descriptor_write[0]))); + EXIT_IF(binding_num >= B_MAX); descriptor_write[binding_num].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write[binding_num].pNext = nullptr; descriptor_write[binding_num].dstSet = new_set->set; - descriptor_write[binding_num].dstBinding = binding_num; + descriptor_write[binding_num].dstBinding = bind.samplers.binding_index; descriptor_write[binding_num].dstArrayElement = 0; descriptor_write[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptor_write[binding_num].descriptorCount = samplers_num; @@ -2667,11 +2683,11 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, int storage_buf if (gds_buffers_num > 0) { - EXIT_IF(binding_num >= static_cast(sizeof(descriptor_write) / sizeof(descriptor_write[0]))); + EXIT_IF(binding_num >= B_MAX); descriptor_write[binding_num].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write[binding_num].pNext = nullptr; descriptor_write[binding_num].dstSet = new_set->set; - descriptor_write[binding_num].dstBinding = binding_num; + descriptor_write[binding_num].dstBinding = bind.gds_pointers.binding_index; descriptor_write[binding_num].dstArrayElement = 0; descriptor_write[binding_num].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; descriptor_write[binding_num].descriptorCount = gds_buffers_num; @@ -2772,9 +2788,15 @@ void DescriptorCache::FreeDescriptor(VulkanImage* image) } } -VkDescriptorSetLayout DescriptorCache::GetDescriptorSetLayout(Stage stage, int storage_buffers_num, int textures2d_sampled_num, - int textures2d_storage_num, int samplers_num, int gds_buffers_num) +VkDescriptorSetLayout DescriptorCache::GetDescriptorSetLayout(Stage stage, const ShaderBindResources& bind, + const ShaderBindParameters& bind_params) { + 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; + int samplers_num = bind.samplers.samplers_num; + int gds_buffers_num = bind.gds_pointers.pointers_num; + EXIT_IF(storage_buffers_num < 0 || storage_buffers_num > BUFFERS_MAX); EXIT_IF(textures2d_sampled_num < 0 || textures2d_sampled_num > TEXTURES_SAMPLED_MAX); EXIT_IF(textures2d_storage_num < 0 || textures2d_storage_num > TEXTURES_STORAGE_MAX); @@ -2826,6 +2848,11 @@ void DeleteDescriptor(TextureVulkanImage* image) g_render_ctx->GetDescriptorCache()->FreeDescriptor(image); } +void DeleteDescriptor(StorageTextureVulkanImage* image) +{ + g_render_ctx->GetDescriptorCache()->FreeDescriptor(image); +} + void DeleteDescriptor(RenderTextureVulkanImage* image) { g_render_ctx->GetDescriptorCache()->FreeDescriptor(image); @@ -3138,11 +3165,17 @@ static void PrepareStorageBuffers(const ShaderStorageResources& storage_buffers, } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage** images, uint32_t** sgprs, bool with_sampler) +static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage** images_sampled, VulkanImage** images_storage, + uint32_t** sgprs, const bool* without_sampler) { - EXIT_IF(images == nullptr); + EXIT_IF(images_sampled == nullptr); + EXIT_IF(images_storage == nullptr); EXIT_IF(sgprs == nullptr); EXIT_IF(*sgprs == nullptr); + EXIT_IF(without_sampler == nullptr); + + int index_sampled = 0; + int index_storage = 0; for (int i = 0; i < textures.textures_num; i++) { @@ -3172,7 +3205,12 @@ static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage* EXIT_NOT_IMPLEMENTED(r.MinLodWarn() != 0); EXIT_NOT_IMPLEMENTED(r.CounterBankId() != 0); EXIT_NOT_IMPLEMENTED(r.LodHdwCntEn() != false); - EXIT_NOT_IMPLEMENTED(r.MemoryType() != 0x10); + EXIT_NOT_IMPLEMENTED(r.MemoryType() != 0x10 && r.MemoryType() != 0x6d); + + bool read_only = (r.MemoryType() == 0x10); + + 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; @@ -3192,17 +3230,34 @@ static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage* if (tex == nullptr) { - TextureObject vulkan_texture_info(r.Dfmt(), r.Nfmt(), width, height, pitch, levels, tile, neo, swizzle, - (with_sampler ? TextureObject::TEXTURE_USAGE_SAMPLED : TextureObject::TEXTURE_USAGE_STORAGE)); + if (without_sampler[i]) + { + StorageTextureObject vulkan_texture_info(r.Dfmt(), r.Nfmt(), width, height, pitch, 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(), addr, size, vulkan_texture_info)); + } else + { + TextureObject vulkan_texture_info(r.Dfmt(), r.Nfmt(), width, height, pitch, levels, tile, neo, swizzle); + + tex = + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, vulkan_texture_info)); + } } EXIT_NOT_IMPLEMENTED(tex == nullptr); - images[i] = tex; - - r.UpdateAddress(i); + if (without_sampler[i]) + { + images_storage[index_storage] = tex; + r.UpdateAddress(index_storage); + index_storage++; + } else + { + images_sampled[index_sampled] = tex; + r.UpdateAddress(index_sampled); + index_sampled++; + } EXIT_NOT_IMPLEMENTED((r.Base() >> 32u) != 0); @@ -3243,16 +3298,16 @@ static void PrepareSamplers(const ShaderSamplerResources& samplers, uint64_t* sa EXIT_NOT_IMPLEMENTED(r.TruncCoord() != false); EXIT_NOT_IMPLEMENTED(r.DisableCubeWrap() != false); EXIT_NOT_IMPLEMENTED(r.FilterMode() != 0); - EXIT_NOT_IMPLEMENTED(r.MinLod() != 0); - EXIT_NOT_IMPLEMENTED(r.MaxLod() != 4095); + // EXIT_NOT_IMPLEMENTED(r.MinLod() != 0); + // EXIT_NOT_IMPLEMENTED(r.MaxLod() != 4095); EXIT_NOT_IMPLEMENTED(r.PerfMip() != 0); EXIT_NOT_IMPLEMENTED(r.PerfZ() != 0); EXIT_NOT_IMPLEMENTED(r.LodBias() != 0); EXIT_NOT_IMPLEMENTED(r.LodBiasSec() != 0); - EXIT_NOT_IMPLEMENTED(r.XyMagFilter() != 1); - EXIT_NOT_IMPLEMENTED(r.XyMinFilter() != 1); + // EXIT_NOT_IMPLEMENTED(r.XyMagFilter() != 1); + // EXIT_NOT_IMPLEMENTED(r.XyMinFilter() != 1); EXIT_NOT_IMPLEMENTED(r.ZFilter() != 1); - EXIT_NOT_IMPLEMENTED(r.MipFilter() != 0 && r.MipFilter() != 2); + // EXIT_NOT_IMPLEMENTED(r.MipFilter() != 0 && r.MipFilter() != 2); EXIT_NOT_IMPLEMENTED(r.BorderColorPtr() != 0); EXIT_NOT_IMPLEMENTED(r.BorderColorType() != 0); @@ -3297,9 +3352,9 @@ static void BindDescriptors(VkCommandBuffer vk_buffer, VkPipelineBindPoint pipel { EXIT_NOT_IMPLEMENTED(bind.push_constant_size > DescriptorCache::PUSH_CONSTANTS_MAX * 4); EXIT_NOT_IMPLEMENTED(bind.storage_buffers.buffers_num > DescriptorCache::BUFFERS_MAX); - EXIT_NOT_IMPLEMENTED( - (bind_params.textures2D_without_sampler && bind.textures2D.textures_num > DescriptorCache::TEXTURES_STORAGE_MAX) || - (!bind_params.textures2D_without_sampler && bind.textures2D.textures_num > DescriptorCache::TEXTURES_SAMPLED_MAX)); + EXIT_NOT_IMPLEMENTED((bind_params.textures2d_storage_num > DescriptorCache::TEXTURES_STORAGE_MAX) || + (bind_params.textures2d_sampled_num > DescriptorCache::TEXTURES_SAMPLED_MAX)); + EXIT_NOT_IMPLEMENTED(bind_params.textures2d_storage_num + bind_params.textures2d_sampled_num != bind.textures2D.textures_num); EXIT_NOT_IMPLEMENTED(bind.samplers.samplers_num > DescriptorCache::SAMPLERS_MAX); VulkanBuffer* storage_buffers[DescriptorCache::BUFFERS_MAX]; @@ -3318,13 +3373,7 @@ static void BindDescriptors(VkCommandBuffer vk_buffer, VkPipelineBindPoint pipel } if (bind.textures2D.textures_num > 0) { - if (bind_params.textures2D_without_sampler) - { - PrepareTextures(bind.textures2D, textures2d_storage, &sgprs_ptr, false); - } else - { - PrepareTextures(bind.textures2D, textures2d_sampled, &sgprs_ptr, true); - } + PrepareTextures(bind.textures2D, textures2d_sampled, textures2d_storage, &sgprs_ptr, bind_params.textures2d_without_sampler); } if (bind.samplers.samplers_num > 0) { @@ -3339,10 +3388,7 @@ static void BindDescriptors(VkCommandBuffer vk_buffer, VkPipelineBindPoint pipel EXIT_IF(bind.push_constant_size != (sgprs_ptr - sgprs) * 4); auto* descriptor_set = g_render_ctx->GetDescriptorCache()->GetDescriptor( - stage, bind.storage_buffers.buffers_num, storage_buffers, - (bind_params.textures2D_without_sampler ? 0 : bind.textures2D.textures_num), textures2d_sampled, - (bind_params.textures2D_without_sampler ? bind.textures2D.textures_num : 0), textures2d_storage, bind.samplers.samplers_num, - samplers, (gds_buffer != nullptr ? 1 : 0), &gds_buffer); + stage, storage_buffers, textures2d_sampled, textures2d_storage, samplers, &gds_buffer, bind, bind_params); EXIT_IF(descriptor_set == nullptr); vkCmdBindDescriptorSets(vk_buffer, pipeline_bind_point, layout, bind.descriptor_set_slot, 1, &descriptor_set->set, 0, nullptr); @@ -3565,8 +3611,8 @@ void GraphicsRenderDrawIndexAuto(CommandBuffer* buffer, HardwareContext* ctx, Us { case 4: vkCmdDraw(vk_buffer, index_count, 1, 0, 0); break; case 17: - EXIT_NOT_IMPLEMENTED(!(vertex_shader_info.vs_embedded && vertex_shader_info.vs_embedded_id == 0 && index_count == 3 && - vs_input_info.buffers_num == 0)); + EXIT_NOT_IMPLEMENTED(!(/*vertex_shader_info.vs_embedded && vertex_shader_info.vs_embedded_id == 0 &&*/ + index_count == 3 && vs_input_info.buffers_num == 0)); vkCmdDraw(vk_buffer, 4, 1, 0, 0); break; case 19: @@ -3662,7 +3708,7 @@ void GraphicsRenderRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, u 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 = 1; + image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.layerCount = 1; @@ -4221,7 +4267,7 @@ VulkanFramebuffer* CommandBuffer::BeginRenderPass(RenderColorInfo* color, Render image_memory_barrier.image = color->vulkan_buffer->image; image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_memory_barrier.subresourceRange.baseMipLevel = 0; - image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.layerCount = 1; diff --git a/source/emulator/src/Graphics/GraphicsRun.cpp b/source/emulator/src/Graphics/GraphicsRun.cpp index 1845cbe..aacfc79 100644 --- a/source/emulator/src/Graphics/GraphicsRun.cpp +++ b/source/emulator/src/Graphics/GraphicsRun.cpp @@ -937,6 +937,8 @@ void CommandProcessor::Run(uint32_t* data, uint32_t num_dw) auto s = pfunc(this, cmd_id, cmd, dw, num_dw); + // printf("\t %05" PRIx32 ": %u\n", num_dw - dw, s); + cmd += s; dw -= s + 1; } diff --git a/source/emulator/src/Graphics/Objects/DepthStencilBuffer.cpp b/source/emulator/src/Graphics/Objects/DepthStencilBuffer.cpp index 16d084f..b0c0013 100644 --- a/source/emulator/src/Graphics/Objects/DepthStencilBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/DepthStencilBuffer.cpp @@ -13,8 +13,14 @@ namespace Kyty::Libs::Graphics { -void* DepthStencilBufferObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, - VulkanMemory* mem) const +static void update_func(GraphicContext* /*ctx*/, const uint64_t* /*params*/, void* /*obj*/, const uint64_t* /*vaddr*/, + const uint64_t* /*size*/, int /*vaddr_num*/) +{ + KYTY_PROFILER_BLOCK("DepthStencilBufferObject::update_func"); +} + +static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + VulkanMemory* mem) { KYTY_PROFILER_BLOCK("DepthStencilBufferObject::Create"); @@ -22,9 +28,9 @@ void* DepthStencilBufferObject::Create(GraphicContext* ctx, const uint64_t* vadd EXIT_IF(mem == nullptr); EXIT_IF(ctx == nullptr); - auto pixel_format = static_cast(params[PARAM_FORMAT]); - auto width = params[PARAM_WIDTH]; - auto height = params[PARAM_HEIGHT]; + auto pixel_format = static_cast(params[DepthStencilBufferObject::PARAM_FORMAT]); + auto width = params[DepthStencilBufferObject::PARAM_WIDTH]; + auto height = params[DepthStencilBufferObject::PARAM_HEIGHT]; EXIT_NOT_IMPLEMENTED(pixel_format == VK_FORMAT_UNDEFINED); EXIT_NOT_IMPLEMENTED(width == 0); @@ -74,7 +80,7 @@ void* DepthStencilBufferObject::Create(GraphicContext* ctx, const uint64_t* vadd // EXIT_NOT_IMPLEMENTED(mem->requirements.size > *size); - GetUpdateFunc()(ctx, params, vk_obj, vaddr, size, vaddr_num); + update_func(ctx, params, vk_obj, vaddr, size, vaddr_num); VkImageViewCreateInfo create_info {}; create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -102,18 +108,6 @@ void* DepthStencilBufferObject::Create(GraphicContext* ctx, const uint64_t* vadd return vk_obj; } -static void update_func(GraphicContext* /*ctx*/, const uint64_t* /*params*/, void* /*obj*/, const uint64_t* /*vaddr*/, - const uint64_t* /*size*/, int /*vaddr_num*/) -{ - KYTY_PROFILER_BLOCK("DepthStencilBufferObject::update_func"); -} - -bool DepthStencilBufferObject::Equal(const uint64_t* other) const -{ - return (params[PARAM_FORMAT] == other[PARAM_FORMAT] && params[PARAM_WIDTH] == other[PARAM_WIDTH] && - params[PARAM_HEIGHT] == other[PARAM_HEIGHT] && params[PARAM_HTILE] == other[PARAM_HTILE]); -} - static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) { KYTY_PROFILER_BLOCK("DepthStencilBufferObject::delete_func"); @@ -134,6 +128,17 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) delete vk_obj; } +bool DepthStencilBufferObject::Equal(const uint64_t* other) const +{ + return (params[PARAM_FORMAT] == other[PARAM_FORMAT] && params[PARAM_WIDTH] == other[PARAM_WIDTH] && + params[PARAM_HEIGHT] == other[PARAM_HEIGHT] && params[PARAM_HTILE] == other[PARAM_HTILE]); +} + +GpuObject::create_func_t DepthStencilBufferObject::GetCreateFunc() const +{ + return create_func; +} + GpuObject::delete_func_t DepthStencilBufferObject::GetDeleteFunc() const { return delete_func; diff --git a/source/emulator/src/Graphics/Objects/GpuMemory.cpp b/source/emulator/src/Graphics/Objects/GpuMemory.cpp index f06f3c8..e039c20 100644 --- a/source/emulator/src/Graphics/Objects/GpuMemory.cpp +++ b/source/emulator/src/Graphics/Objects/GpuMemory.cpp @@ -120,9 +120,8 @@ private: struct ObjectInfo { - void* obj = nullptr; + GpuMemoryObject object; uint64_t params[GpuObject::PARAMS_MAX] = {}; - GpuMemoryObjectType type = GpuMemoryObjectType::Invalid; uint64_t hash[VADDR_BLOCKS_MAX] = {}; GpuObject::write_back_func_t write_back_func = nullptr; GpuObject::delete_func_t delete_func = nullptr; @@ -378,7 +377,13 @@ static uint64_t calc_hash(const uint8_t* buf, uint64_t size) void GpuMemory::Link(int id1, int id2, OverlapType rel) { - EXIT_NOT_IMPLEMENTED(rel != OverlapType::Equals); + OverlapType other_rel = OverlapType::None; + switch (rel) + { + case OverlapType::Equals: other_rel = OverlapType::Equals; break; + case OverlapType::IsContainedWithin: other_rel = OverlapType::Contains; break; + default: EXIT("invalid rel: %s\n", Core::EnumName(rel).C_Str()); + } auto& h1 = m_objects[id1]; EXIT_IF(h1.free); @@ -386,11 +391,11 @@ 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()); + // EXIT_NOT_IMPLEMENTED(!h1.others.IsEmpty()); + // EXIT_NOT_IMPLEMENTED(!h2.others.IsEmpty()); h1.others.Add({rel, id2}); - h2.others.Add({rel, id1}); + h2.others.Add({other_rel, id1}); } void GpuMemory::Update(GraphicContext* ctx, ObjectInfo& o, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const uint64_t* hash) @@ -400,8 +405,8 @@ void GpuMemory::Update(GraphicContext* ctx, ObjectInfo& o, const uint64_t* vaddr { if (o.hash[vi] != hash[vi]) { - printf("Update (CPU -> GPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", Core::EnumName(o.type).C_Str(), - vaddr[vi], size[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]; } @@ -409,7 +414,7 @@ void GpuMemory::Update(GraphicContext* ctx, ObjectInfo& o, const uint64_t* vaddr if (need_update) { EXIT_IF(o.update_func == nullptr); - o.update_func(ctx, o.params, o.obj, vaddr, size, vaddr_num); + o.update_func(ctx, o.params, o.object.obj, vaddr, size, vaddr_num); } } @@ -436,8 +441,9 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const } } - bool overlap = false; - bool delete_all = false; + bool overlap = false; + bool delete_all = false; + bool create_from_objects = false; auto others = FindBlocks(vaddr, size, vaddr_num); @@ -448,7 +454,7 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const auto& h = m_objects[obj.object_id]; EXIT_IF(h.free); auto& o = h.info; - if (obj.relation == OverlapType::Equals && o.type == info.type && info.Equal(o.params)) + if (obj.relation == OverlapType::Equals && o.object.type == info.type && info.Equal(o.params)) { Update(ctx, o, vaddr, size, vaddr_num, hash); @@ -457,7 +463,7 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const o.in_use = true; o.read_only = info.read_only; o.check_hash = info.check_hash; - return o.obj; + return o.object.obj; } } @@ -468,7 +474,7 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const EXIT_IF(h.free); auto& o = h.info; - switch (ObjectsRelation(o.type, obj.relation, info.type)) + switch (ObjectsRelation(o.object.type, obj.relation, info.type)) { case ObjectsRelation(GpuMemoryObjectType::StorageBuffer, OverlapType::Equals, GpuMemoryObjectType::RenderTexture): case ObjectsRelation(GpuMemoryObjectType::VideoOutBuffer, OverlapType::Equals, GpuMemoryObjectType::StorageBuffer): @@ -482,17 +488,23 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const delete_all = true; break; } + case ObjectsRelation(GpuMemoryObjectType::StorageTexture, OverlapType::Equals, GpuMemoryObjectType::Texture): + { + overlap = true; + create_from_objects = true; + break; + } default: - EXIT("unknown relation: %s - %s - %s\n", Core::EnumName(o.type).C_Str(), Core::EnumName(obj.relation).C_Str(), + 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()); } } else { OverlapType rel = others.At(0).relation; - GpuMemoryObjectType type = m_objects[others.At(0).object_id].info.type; + GpuMemoryObjectType type = m_objects[others.At(0).object_id].info.object.type; for (const auto& obj: others) { - EXIT_NOT_IMPLEMENTED(rel != obj.relation || type != m_objects[obj.object_id].info.type); + EXIT_NOT_IMPLEMENTED(rel != obj.relation || type != m_objects[obj.object_id].info.object.type); } switch (ObjectsRelation(type, rel, info.type)) // NOLINT @@ -500,6 +512,10 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const 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()); @@ -529,13 +545,29 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const o.params[i] = info.params[i]; } - o.type = info.type; - o.obj = nullptr; + o.object.type = info.type; + o.object.obj = nullptr; for (int vi = 0; vi < vaddr_num; vi++) { o.hash[vi] = hash[vi]; } - o.obj = info.Create(ctx, vaddr, size, vaddr_num, &o.mem); + + if (create_from_objects) + { + Vector objects; + for (const auto& obj: others) + { + const auto& o2 = m_objects[obj.object_id].info; + objects.Add(o2.object); + } + auto create_func = info.GetCreateFromObjectsFunc(); + EXIT_IF(create_func == nullptr); + o.object.obj = create_func(ctx, o.params, objects, &o.mem); + } else + { + o.object.obj = info.GetCreateFunc()(ctx, o.params, vaddr, size, vaddr_num, &o.mem); + } + o.write_back_func = info.GetWriteBackFunc(); o.delete_func = info.GetDeleteFunc(); o.update_func = info.GetUpdateFunc(); @@ -574,12 +606,13 @@ void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const if (overlap) { - EXIT_NOT_IMPLEMENTED(others.Size() != 1); - - Link(index, others.At(0).object_id, others.At(0).relation); + for (const auto& obj: others) + { + Link(index, obj.object_id, obj.relation); + } } - return o.obj; + return o.object.obj; } Vector GpuMemory::FindObjects(const uint64_t* vaddr, const uint64_t* size, int vaddr_num) @@ -603,10 +636,10 @@ Vector GpuMemory::FindObjects(const uint64_t* vaddr, const uint { 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.type).C_Str()); + 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) { - ret.Add({h.info.type, h.info.obj}); + ret.Add(h.info.object); } } @@ -634,13 +667,13 @@ void GpuMemory::ResetHash(GraphicContext* /*ctx*/, const uint64_t* vaddr, const EXIT_IF(h.free); auto& o = h.info; - if (o.type == type) + if (o.object.type == type) { 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 ", new_hash = 0x%016" PRIx64 "\n", - Core::EnumName(o.type).C_Str(), vaddr[vi], size[vi], o.hash[vi], new_hash); + Core::EnumName(o.object.type).C_Str(), vaddr[vi], size[vi], o.hash[vi], new_hash); o.hash[vi] = new_hash; } @@ -699,10 +732,10 @@ void GpuMemory::Free(GraphicContext* ctx, int object_id) // EXIT_IF(block.free); for (int vi = 0; vi < block.vaddr_num; vi++) { - printf("Delete: type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", Core::EnumName(o.type).C_Str(), + printf("Delete: type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", Core::EnumName(o.object.type).C_Str(), block.vaddr[vi], block.size[vi]); } - o.delete_func(ctx, o.obj, &o.mem); + o.delete_func(ctx, o.object.obj, &o.mem); } h.free = true; DeleteBlock(&h.block); @@ -840,7 +873,7 @@ void GpuMemory::WriteBack(GraphicContext* ctx) auto& block = h.block; // EXIT_IF(block.free); - o.write_back_func(ctx, o.obj, 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++) { @@ -853,7 +886,7 @@ void GpuMemory::WriteBack(GraphicContext* ctx) 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.type).C_Str(), block.vaddr[vi], block.size[vi], o.hash[vi], new_hash); + Core::EnumName(o.object.type).C_Str(), block.vaddr[vi], block.size[vi], o.hash[vi], new_hash); o.hash[vi] = new_hash; } @@ -889,7 +922,7 @@ void GpuMemory::Flush(GraphicContext* ctx) auto& o = h.info; EXIT_IF(o.update_func == nullptr); - o.update_func(ctx, o.params, o.obj, block.vaddr, block.size, block.vaddr_num); + o.update_func(ctx, o.params, o.object.obj, block.vaddr, block.size, block.vaddr_num); } } } @@ -1012,13 +1045,13 @@ void GpuMemory::DbgDbDump() (r.block.vaddr_num > 0 ? m_db_add_object->BindString(":size", hex(r.block.size[0])) : m_db_add_object->BindNull(":size")); (r.block.vaddr_num > 1 ? m_db_add_object->BindString(":size2", hex(r.block.size[1])) : m_db_add_object->BindNull(":size2")); (r.block.vaddr_num > 2 ? m_db_add_object->BindString(":size3", hex(r.block.size[2])) : m_db_add_object->BindNull(":size3")); - m_db_add_object->BindString(":obj", hex(r.info.obj)); + m_db_add_object->BindString(":obj", hex(r.info.object.obj)); int param0_index = m_db_add_object->GetIndex(":param0"); for (int i = 0; i < GpuObject::PARAMS_MAX; i++) { m_db_add_object->BindInt64(param0_index + i, static_cast(r.info.params[i])); } - m_db_add_object->BindString(":type", Core::EnumName(r.info.type).C_Str()); + m_db_add_object->BindString(":type", Core::EnumName(r.info.object.type).C_Str()); int hash0_index = m_db_add_object->GetIndex(":hash"); for (int i = 0; i < VADDR_BLOCKS_MAX; i++) { @@ -1120,7 +1153,7 @@ void GpuMemory::DbgDump() } } auto& o = h.info; - printf("\t type = %s\n", Core::EnumName(o.type).C_Str()); + 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]); diff --git a/source/emulator/src/Graphics/Objects/IndexBuffer.cpp b/source/emulator/src/Graphics/Objects/IndexBuffer.cpp index dab0f14..1312772 100644 --- a/source/emulator/src/Graphics/Objects/IndexBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/IndexBuffer.cpp @@ -12,7 +12,8 @@ namespace Kyty::Libs::Graphics { -void* IndexBufferGpuObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const +static void* create_func(GraphicContext* ctx, const uint64_t* /*params*/, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + VulkanMemory* mem) { KYTY_PROFILER_BLOCK("IndexBufferGpuObject::Create"); @@ -59,11 +60,6 @@ static void update_func(GraphicContext* /*ctx*/, const uint64_t* /*params*/, voi KYTY_NOT_IMPLEMENTED; } -bool IndexBufferGpuObject::Equal(const uint64_t* /*other*/) const -{ - return true; -} - static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* /*mem*/) { KYTY_PROFILER_BLOCK("IndexBufferGpuObject::delete_func"); @@ -79,6 +75,16 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* /*mem*/) delete vk_obj; } +bool IndexBufferGpuObject::Equal(const uint64_t* /*other*/) const +{ + return true; +} + +GpuObject::create_func_t IndexBufferGpuObject::GetCreateFunc() const +{ + return create_func; +} + GpuObject::delete_func_t IndexBufferGpuObject::GetDeleteFunc() const { return delete_func; diff --git a/source/emulator/src/Graphics/Objects/Label.cpp b/source/emulator/src/Graphics/Objects/Label.cpp index 0d8b448..6588743 100644 --- a/source/emulator/src/Graphics/Objects/Label.cpp +++ b/source/emulator/src/Graphics/Objects/Label.cpp @@ -330,7 +330,8 @@ void LabelSet(CommandBuffer* buffer, Label* label) g_label_manager->Set(buffer, label); } -void* LabelGpuObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* /*mem*/) const +static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + VulkanMemory* /*mem*/) { KYTY_PROFILER_BLOCK("LabelGpuObject::Create"); @@ -338,15 +339,15 @@ void* LabelGpuObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const u EXIT_NOT_IMPLEMENTED(*size != 8 && *size != 4); - auto value = params[PARAM_VALUE]; - auto callback_1 = reinterpret_cast(params[PARAM_CALLBACK_1]); - auto callback_2 = reinterpret_cast(params[PARAM_CALLBACK_2]); + auto value = params[LabelGpuObject::PARAM_VALUE]; + auto callback_1 = reinterpret_cast(params[LabelGpuObject::PARAM_CALLBACK_1]); + auto callback_2 = reinterpret_cast(params[LabelGpuObject::PARAM_CALLBACK_2]); - auto* label_obj = - (*size == 8 ? LabelCreate(ctx, reinterpret_cast(*vaddr), value, callback_1, callback_2, params + PARAM_ARG_1) - : (*size == 4 ? LabelCreate(ctx, reinterpret_cast(*vaddr), static_cast(value), callback_1, - callback_2, params + PARAM_ARG_1) - : nullptr)); + auto* label_obj = (*size == 8 ? LabelCreate(ctx, reinterpret_cast(*vaddr), value, callback_1, callback_2, + params + LabelGpuObject::PARAM_ARG_1) + : (*size == 4 ? LabelCreate(ctx, reinterpret_cast(*vaddr), static_cast(value), + callback_1, callback_2, params + LabelGpuObject::PARAM_ARG_1) + : nullptr)); EXIT_NOT_IMPLEMENTED(label_obj == nullptr); @@ -361,14 +362,6 @@ static void update_func(GraphicContext* /*ctx*/, const uint64_t* /*params*/, voi KYTY_NOT_IMPLEMENTED; } -bool LabelGpuObject::Equal(const uint64_t* other) const -{ - return (params[PARAM_VALUE] == other[PARAM_VALUE] && params[PARAM_CALLBACK_1] == other[PARAM_CALLBACK_1] && - params[PARAM_CALLBACK_2] == other[PARAM_CALLBACK_2] && params[PARAM_ARG_1] == other[PARAM_ARG_1] && - params[PARAM_ARG_2] == other[PARAM_ARG_2] && params[PARAM_ARG_3] == other[PARAM_ARG_3] && - params[PARAM_ARG_4] == other[PARAM_ARG_4]); -} - static void delete_func(GraphicContext* /*ctx*/, void* obj, VulkanMemory* /*mem*/) { KYTY_PROFILER_BLOCK("LabelGpuObject::delete_func"); @@ -380,6 +373,19 @@ static void delete_func(GraphicContext* /*ctx*/, void* obj, VulkanMemory* /*mem* LabelDelete(label_obj); } +bool LabelGpuObject::Equal(const uint64_t* other) const +{ + return (params[PARAM_VALUE] == other[PARAM_VALUE] && params[PARAM_CALLBACK_1] == other[PARAM_CALLBACK_1] && + params[PARAM_CALLBACK_2] == other[PARAM_CALLBACK_2] && params[PARAM_ARG_1] == other[PARAM_ARG_1] && + params[PARAM_ARG_2] == other[PARAM_ARG_2] && params[PARAM_ARG_3] == other[PARAM_ARG_3] && + params[PARAM_ARG_4] == other[PARAM_ARG_4]); +} + +GpuObject::create_func_t LabelGpuObject::GetCreateFunc() const +{ + return create_func; +} + GpuObject::delete_func_t LabelGpuObject::GetDeleteFunc() const { return delete_func; diff --git a/source/emulator/src/Graphics/Objects/RenderTexture.cpp b/source/emulator/src/Graphics/Objects/RenderTexture.cpp index 2b3a7b5..7f4a194 100644 --- a/source/emulator/src/Graphics/Objects/RenderTexture.cpp +++ b/source/emulator/src/Graphics/Objects/RenderTexture.cpp @@ -14,7 +14,60 @@ namespace Kyty::Libs::Graphics { -void* RenderTextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const +static bool buffer_is_tiled(uint64_t vaddr, uint64_t size) +{ + if ((size & 0x7u) == 0) + { + const auto* ptr = reinterpret_cast(vaddr); + const auto* ptr_end = reinterpret_cast(vaddr + size / 8); + for (uint64_t element = *ptr; ptr < ptr_end; ptr++) + { + if (element != *ptr) + { + return true; + } + } + return false; + } + return true; +} + +static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + KYTY_PROFILER_BLOCK("RenderTextureObject::update_func"); + + EXIT_IF(obj == nullptr); + EXIT_IF(ctx == nullptr); + EXIT_IF(params == nullptr); + EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); + + 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 (tiled && buffer_is_tiled(*vaddr, *size)) + { + EXIT_NOT_IMPLEMENTED(width != pitch); + auto* temp_buf = new uint8_t[*size]; + KYTY_NOT_IMPLEMENTED; + // TODO() + // TileConvertTiledToLinear(temp_buf, reinterpret_cast(*vaddr), TileMode::VideoOutTiled, width, height, neo); + // UtilFillImage(ctx, vk_obj, temp_buf, *size, pitch); + delete[] temp_buf; + } else + { + UtilFillImage(ctx, vk_obj, reinterpret_cast(*vaddr), *size, pitch); + } +} + +static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + VulkanMemory* mem) { KYTY_PROFILER_BLOCK("RenderTextureObject::Create"); @@ -22,9 +75,9 @@ void* RenderTextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, co EXIT_IF(mem == nullptr); EXIT_IF(ctx == nullptr); - auto pixel_format = params[PARAM_FORMAT]; - auto width = params[PARAM_WIDTH]; - auto height = params[PARAM_HEIGHT]; + 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; @@ -89,7 +142,7 @@ void* RenderTextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, co // EXIT_NOT_IMPLEMENTED(mem->requirements.size > *size); - GetUpdateFunc()(ctx, params, vk_obj, vaddr, size, vaddr_num); + update_func(ctx, params, vk_obj, vaddr, size, vaddr_num); VkImageViewCreateInfo create_info {}; create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -115,65 +168,6 @@ void* RenderTextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, co return vk_obj; } -static bool buffer_is_tiled(uint64_t vaddr, uint64_t size) -{ - if ((size & 0x7u) == 0) - { - const auto* ptr = reinterpret_cast(vaddr); - const auto* ptr_end = reinterpret_cast(vaddr + size / 8); - for (uint64_t element = *ptr; ptr < ptr_end; ptr++) - { - if (element != *ptr) - { - return true; - } - } - return false; - } - return true; -} - -static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num) -{ - KYTY_PROFILER_BLOCK("RenderTextureObject::update_func"); - - EXIT_IF(obj == nullptr); - EXIT_IF(ctx == nullptr); - EXIT_IF(params == nullptr); - EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); - - 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 (tiled && buffer_is_tiled(*vaddr, *size)) - { - EXIT_NOT_IMPLEMENTED(width != pitch); - auto* temp_buf = new uint8_t[*size]; - KYTY_NOT_IMPLEMENTED; - // TODO() - // TileConvertTiledToLinear(temp_buf, reinterpret_cast(*vaddr), TileMode::VideoOutTiled, width, height, neo); - // UtilFillImage(ctx, vk_obj, temp_buf, *size, pitch); - delete[] temp_buf; - } else - { - UtilFillImage(ctx, vk_obj, reinterpret_cast(*vaddr), *size, pitch); - } -} - -bool RenderTextureObject::Equal(const uint64_t* other) const -{ - return (params[PARAM_FORMAT] == other[PARAM_FORMAT] && params[PARAM_WIDTH] == other[PARAM_WIDTH] && - params[PARAM_HEIGHT] == other[PARAM_HEIGHT] && params[PARAM_TILED] == other[PARAM_TILED] && - params[PARAM_PITCH] == other[PARAM_PITCH] && params[PARAM_PITCH] == other[PARAM_PITCH]); -} - static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) { KYTY_PROFILER_BLOCK("RenderTextureObject::delete_func"); @@ -196,6 +190,18 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) delete vk_obj; } +bool RenderTextureObject::Equal(const uint64_t* other) const +{ + return (params[PARAM_FORMAT] == other[PARAM_FORMAT] && params[PARAM_WIDTH] == other[PARAM_WIDTH] && + params[PARAM_HEIGHT] == other[PARAM_HEIGHT] && params[PARAM_TILED] == other[PARAM_TILED] && + params[PARAM_PITCH] == other[PARAM_PITCH] && params[PARAM_PITCH] == other[PARAM_PITCH]); +} + +GpuObject::create_func_t RenderTextureObject::GetCreateFunc() const +{ + return create_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 e59b319..341d3d5 100644 --- a/source/emulator/src/Graphics/Objects/StorageBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/StorageBuffer.cpp @@ -12,31 +12,6 @@ namespace Kyty::Libs::Graphics { -void* StorageBufferGpuObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, - VulkanMemory* mem) const -{ - KYTY_PROFILER_BLOCK("StorageBufferGpuObject::Create"); - - EXIT_IF(vaddr_num != 1 || size == nullptr || vaddr == nullptr || *vaddr == 0); - - EXIT_IF(mem == nullptr); - EXIT_IF(ctx == nullptr); - - auto* vk_obj = new VulkanBuffer; - - 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 | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - vk_obj->buffer = nullptr; - - VulkanCreateBuffer(ctx, *size, vk_obj); - EXIT_NOT_IMPLEMENTED(vk_obj->buffer == nullptr); - - GetUpdateFunc()(ctx, params, vk_obj, vaddr, size, vaddr_num); - - return vk_obj; -} - static void update_func(GraphicContext* ctx, const uint64_t* /*params*/, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num) { @@ -56,9 +31,29 @@ static void update_func(GraphicContext* ctx, const uint64_t* /*params*/, void* o VulkanUnmapMemory(ctx, &vk_obj->memory); } -bool StorageBufferGpuObject::Equal(const uint64_t* other) const +static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + VulkanMemory* mem) { - return params[0] == other[0] && params[1] == other[1]; + KYTY_PROFILER_BLOCK("StorageBufferGpuObject::Create"); + + EXIT_IF(vaddr_num != 1 || size == nullptr || vaddr == nullptr || *vaddr == 0); + + EXIT_IF(mem == nullptr); + EXIT_IF(ctx == nullptr); + + auto* vk_obj = new VulkanBuffer; + + 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 | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + vk_obj->buffer = nullptr; + + VulkanCreateBuffer(ctx, *size, vk_obj); + EXIT_NOT_IMPLEMENTED(vk_obj->buffer == nullptr); + + update_func(ctx, params, vk_obj, vaddr, size, vaddr_num); + + return vk_obj; } static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* /*mem*/) @@ -103,6 +98,16 @@ static void write_back(GraphicContext* ctx, void* obj, const uint64_t* vaddr, co KYTY_PROFILER_END_BLOCK; } +bool StorageBufferGpuObject::Equal(const uint64_t* other) const +{ + return params[0] == other[0] && params[1] == other[1]; +} + +GpuObject::create_func_t StorageBufferGpuObject::GetCreateFunc() const +{ + return create_func; +} + GpuObject::write_back_func_t StorageBufferGpuObject::GetWriteBackFunc() const { return write_back; diff --git a/source/emulator/src/Graphics/Objects/StorageTexture.cpp b/source/emulator/src/Graphics/Objects/StorageTexture.cpp new file mode 100644 index 0000000..3949d31 --- /dev/null +++ b/source/emulator/src/Graphics/Objects/StorageTexture.cpp @@ -0,0 +1,358 @@ +#include "Emulator/Graphics/Objects/StorageTexture.h" + +#include "Kyty/Core/DbgAssert.h" +#include "Kyty/Core/Vector.h" + +#include "Emulator/Config.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" + +#include + +#ifdef KYTY_EMU_ENABLED + +namespace Kyty::Libs::Graphics { + +static VkFormat get_texture_format(uint32_t dfmt, uint32_t nfmt) +{ + if (nfmt == 9 && dfmt == 10) + { + return VK_FORMAT_R8G8B8A8_SRGB; + } + if (nfmt == 0 && dfmt == 10) + { + return VK_FORMAT_R8G8B8A8_UNORM; + } + if (nfmt == 9 && dfmt == 37) + { + return VK_FORMAT_BC3_SRGB_BLOCK; + } + EXIT("unknown format: nfmt = %u, dfmt = %u\n", nfmt, dfmt); + return VK_FORMAT_UNDEFINED; +} + +static VkComponentSwizzle get_swizzle(uint8_t s) +{ + switch (s) + { + case 0: return VK_COMPONENT_SWIZZLE_ZERO; break; + case 1: return VK_COMPONENT_SWIZZLE_ONE; break; + case 4: return VK_COMPONENT_SWIZZLE_R; break; + case 5: return VK_COMPONENT_SWIZZLE_G; break; + case 6: return VK_COMPONENT_SWIZZLE_B; break; + case 7: return VK_COMPONENT_SWIZZLE_A; break; + case 2: + case 3: + default: EXIT("unknown swizzle: %d\n", static_cast(s)); + } + return VK_COMPONENT_SWIZZLE_IDENTITY; +} + +static VkImageUsageFlags get_usage() +{ + VkImageUsageFlags vk_usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + vk_usage |= VK_IMAGE_USAGE_STORAGE_BIT; + + return vk_usage; +} + +static bool CheckFormat(GraphicContext* ctx, VkImageCreateInfo* image_info) +{ + VkImageFormatProperties props {}; + if (vkGetPhysicalDeviceImageFormatProperties(ctx->physical_device, image_info->format, image_info->imageType, image_info->tiling, + image_info->usage, image_info->flags, &props) == VK_ERROR_FORMAT_NOT_SUPPORTED) + { + if (image_info->format == VK_FORMAT_R8G8B8A8_SRGB) + { + // TODO() convert SRGB -> LINEAR in shader + image_info->format = VK_FORMAT_R8G8B8A8_UNORM; + bool result = CheckFormat(ctx, image_info); + printf("replace VK_FORMAT_R8G8B8A8_SRGB => VK_FORMAT_R8G8B8A8_UNORM [%s]\n", (!result ? "FAIL" : "SUCCESS")); + return result; + } + if (image_info->format == VK_FORMAT_B8G8R8A8_SRGB) + { + // TODO() convert SRGB -> LINEAR in shader + image_info->format = VK_FORMAT_B8G8R8A8_UNORM; + bool result = CheckFormat(ctx, image_info); + printf("replace VK_FORMAT_B8G8R8A8_SRGB => VK_FORMAT_B8G8R8A8_UNORM [%s]\n", (!result ? "FAIL" : "SUCCESS")); + return result; + } + return false; + } + return true; +} + +static bool CheckSwizzle(GraphicContext* /*ctx*/, VkImageCreateInfo* image_info, VkComponentMapping* components) +{ + if ((image_info->usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) + { + if (components->r == VK_COMPONENT_SWIZZLE_R && components->g == VK_COMPONENT_SWIZZLE_G && components->b == VK_COMPONENT_SWIZZLE_B && + components->a == VK_COMPONENT_SWIZZLE_A) + { + return true; + } + + if (components->r == VK_COMPONENT_SWIZZLE_B && components->g == VK_COMPONENT_SWIZZLE_G && components->b == VK_COMPONENT_SWIZZLE_R && + components->a == VK_COMPONENT_SWIZZLE_A && image_info->format == VK_FORMAT_R8G8B8A8_SRGB) + { + printf("replace VK_FORMAT_R8G8B8A8_SRGB => VK_FORMAT_B8G8R8A8_SRGB\n"); + + components->r = VK_COMPONENT_SWIZZLE_R; + components->g = VK_COMPONENT_SWIZZLE_G; + components->b = VK_COMPONENT_SWIZZLE_B; + components->a = VK_COMPONENT_SWIZZLE_A; + image_info->format = VK_FORMAT_B8G8R8A8_SRGB; + return true; + } + + // TODO() swizzle channels in shader + + return false; + } + return true; +} + +static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + KYTY_PROFILER_BLOCK("StorageTextureObject::update_func"); + + EXIT_IF(obj == nullptr); + EXIT_IF(ctx == nullptr); + EXIT_IF(params == nullptr); + EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); + + auto* vk_obj = static_cast(obj); + + auto tile = params[StorageTextureObject::PARAM_TILE]; + 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 pitch = params[StorageTextureObject::PARAM_PITCH]; + bool neo = Config::IsNeo(); + + VkImageLayout vk_layout = VK_IMAGE_LAYOUT_GENERAL; + + EXIT_NOT_IMPLEMENTED(levels >= 16); + + EXIT_NOT_IMPLEMENTED(tile != 8 && tile != 13); + + uint32_t level_sizes[16]; + + TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, nullptr, level_sizes, nullptr, nullptr); + + // dbg_test_mipmaps(ctx, VK_FORMAT_BC3_SRGB_BLOCK, 512, 512); + + uint32_t offset = 0; + uint32_t mip_width = width; + uint32_t mip_height = height; + uint32_t mip_pitch = pitch; + + Vector regions(levels); + for (uint32_t i = 0; i < levels; i++) + { + EXIT_NOT_IMPLEMENTED(level_sizes[i] == 0); + + auto mipmap_offset = UtilCalcMipmapOffset(i, width, height); + + regions[i].offset = offset; + regions[i].width = mip_width; + regions[i].height = mip_height; + regions[i].pitch = mip_pitch; + regions[i].dst_level = 0; + regions[i].dst_x = mipmap_offset.first; + regions[i].dst_y = mipmap_offset.second; + + offset += level_sizes[i]; + + if (mip_width > 1) + { + mip_width /= 2; + } + if (mip_height > 1) + { + mip_height /= 2; + } + if (mip_pitch > 1) + { + mip_pitch /= 2; + } + } + + if (tile == 13) + { + EXIT_NOT_IMPLEMENTED(pitch != width); + auto* temp_buf = new uint8_t[*size]; + TileConvertTiledToLinear(temp_buf, reinterpret_cast(*vaddr), TileMode::TextureTiled, dfmt, nfmt, width, height, levels, neo); + UtilFillImage(ctx, vk_obj, temp_buf, *size, regions, static_cast(vk_layout)); + delete[] temp_buf; + } else if (tile == 8) + { + UtilFillImage(ctx, vk_obj, reinterpret_cast(*vaddr), *size, regions, 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, + VulkanMemory* mem) +{ + KYTY_PROFILER_BLOCK("StorageTextureObject::Create"); + + EXIT_IF(size == nullptr || vaddr == nullptr); + EXIT_IF(mem == nullptr); + 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]; + + VkImageUsageFlags vk_usage = get_usage(); + + VkComponentMapping components {}; + + components.r = get_swizzle(swizzle & 0xffu); + components.g = get_swizzle((swizzle >> 8u) & 0xffu); + components.b = get_swizzle((swizzle >> 16u) & 0xffu); + components.a = get_swizzle((swizzle >> 24u) & 0xffu); + + auto pixel_format = get_texture_format(dfmt, nfmt); + + EXIT_NOT_IMPLEMENTED(pixel_format == VK_FORMAT_UNDEFINED); + EXIT_NOT_IMPLEMENTED(width == 0); + EXIT_NOT_IMPLEMENTED(height == 0); + + if (levels > 1) + { + height += (height > 1 ? height / 2 : 1); + } + + auto* vk_obj = new StorageTextureVulkanImage; + + 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 = width; + image_info.extent.height = height; + image_info.extent.depth = 1; + image_info.mipLevels = 1; + image_info.arrayLayers = 1; + image_info.format = pixel_format; + image_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_info.usage = vk_usage; + image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_info.samples = VK_SAMPLE_COUNT_1_BIT; + + if (!CheckSwizzle(ctx, &image_info, &components)) + { + EXIT("swizzle is not supported"); + } + + if (!CheckFormat(ctx, &image_info)) + { + EXIT("format is not supported"); + } + + vk_obj->extent.width = width; + vk_obj->extent.height = height; + vk_obj->format = image_info.format; + vk_obj->image = nullptr; + vk_obj->image_view = nullptr; + vk_obj->layout = image_info.initialLayout; + + 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; + + update_func(ctx, params, vk_obj, vaddr, size, vaddr_num); + + 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 = components; + 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 = VK_REMAINING_MIP_LEVELS; + + 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("StorageTextureObject::delete_func"); + + auto* vk_obj = reinterpret_cast(obj); + + EXIT_IF(vk_obj == nullptr); + EXIT_IF(ctx == nullptr); + + DeleteDescriptor(vk_obj); + + vkDestroyImageView(ctx->device, vk_obj->image_view, nullptr); + + vkDestroyImage(ctx->device, vk_obj->image, nullptr); + + VulkanFree(ctx, mem); + + delete vk_obj; +} + +bool StorageTextureObject::Equal(const uint64_t* other) const +{ + return (params[PARAM_DFMT_NFMT] == other[PARAM_DFMT_NFMT] && params[PARAM_PITCH] == other[PARAM_PITCH] && + params[PARAM_WIDTH_HEIGHT] == other[PARAM_WIDTH_HEIGHT] && params[PARAM_LEVELS] == other[PARAM_LEVELS] && + params[PARAM_TILE] == other[PARAM_TILE] && params[PARAM_NEO] == other[PARAM_NEO] && + params[PARAM_SWIZZLE] == other[PARAM_SWIZZLE]); +} + +GpuObject::create_func_t StorageTextureObject::GetCreateFunc() const +{ + return create_func; +} + +GpuObject::delete_func_t StorageTextureObject::GetDeleteFunc() const +{ + return delete_func; +} + +GpuObject::update_func_t StorageTextureObject::GetUpdateFunc() const +{ + return update_func; +} + +} // namespace Kyty::Libs::Graphics + +#endif diff --git a/source/emulator/src/Graphics/Objects/Texture.cpp b/source/emulator/src/Graphics/Objects/Texture.cpp index 227cf03..ea22165 100644 --- a/source/emulator/src/Graphics/Objects/Texture.cpp +++ b/source/emulator/src/Graphics/Objects/Texture.cpp @@ -22,6 +22,10 @@ static VkFormat get_texture_format(uint32_t dfmt, uint32_t nfmt) { return VK_FORMAT_R8G8B8A8_SRGB; } + if (nfmt == 0 && dfmt == 10) + { + return VK_FORMAT_R8G8B8A8_UNORM; + } if (nfmt == 9 && dfmt == 37) { return VK_FORMAT_BC3_SRGB_BLOCK; @@ -47,6 +51,15 @@ static VkComponentSwizzle get_swizzle(uint8_t s) return VK_COMPONENT_SWIZZLE_IDENTITY; } +static VkImageUsageFlags get_usage() +{ + VkImageUsageFlags vk_usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + vk_usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + + return vk_usage; +} + static bool CheckFormat(GraphicContext* ctx, VkImageCreateInfo* image_info) { VkImageFormatProperties props {}; @@ -104,30 +117,190 @@ static bool CheckSwizzle(GraphicContext* /*ctx*/, VkImageCreateInfo* image_info, return true; } -void* TextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const +static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + KYTY_PROFILER_BLOCK("TextureObject::update_func"); + + EXIT_IF(obj == nullptr); + EXIT_IF(ctx == nullptr); + EXIT_IF(params == nullptr); + EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); + + auto* vk_obj = static_cast(obj); + + auto tile = params[TextureObject::PARAM_TILE]; + 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 pitch = params[TextureObject::PARAM_PITCH]; + bool neo = Config::IsNeo(); + + VkImageLayout vk_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + EXIT_NOT_IMPLEMENTED(levels >= 16); + + EXIT_NOT_IMPLEMENTED(tile != 8 && tile != 13); + + uint32_t level_sizes[16]; + + TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, nullptr, level_sizes, nullptr, nullptr); + + // dbg_test_mipmaps(ctx, VK_FORMAT_BC3_SRGB_BLOCK, 512, 512); + + uint32_t offset = 0; + uint32_t mip_width = width; + uint32_t mip_height = height; + uint32_t mip_pitch = pitch; + + Vector regions(levels); + for (uint32_t i = 0; i < levels; i++) + { + EXIT_NOT_IMPLEMENTED(level_sizes[i] == 0); + + regions[i].offset = offset; + regions[i].width = mip_width; + regions[i].height = mip_height; + regions[i].pitch = mip_pitch; + regions[i].dst_level = i; + regions[i].dst_x = 0; + regions[i].dst_y = 0; + + offset += level_sizes[i]; + + if (mip_width > 1) + { + mip_width /= 2; + } + if (mip_height > 1) + { + mip_height /= 2; + } + if (mip_pitch > 1) + { + mip_pitch /= 2; + } + } + + if (tile == 13) + { + EXIT_NOT_IMPLEMENTED(pitch != width); + auto* temp_buf = new uint8_t[*size]; + TileConvertTiledToLinear(temp_buf, reinterpret_cast(*vaddr), TileMode::TextureTiled, dfmt, nfmt, width, height, levels, neo); + UtilFillImage(ctx, vk_obj, temp_buf, *size, regions, static_cast(vk_layout)); + delete[] temp_buf; + } else if (tile == 8) + { + UtilFillImage(ctx, vk_obj, reinterpret_cast(*vaddr), *size, regions, static_cast(vk_layout)); + } +} + +static void update2_func(GraphicContext* ctx, const uint64_t* params, void* obj, const Vector& objects) +{ + KYTY_PROFILER_BLOCK("TextureObject::update2_func"); + + EXIT_IF(obj == nullptr); + EXIT_IF(ctx == nullptr); + EXIT_IF(params == nullptr); + EXIT_IF(objects.IsEmpty()); + + auto* vk_obj = static_cast(obj); + + auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u; + auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu; + auto levels = params[TextureObject::PARAM_LEVELS]; + + VkImageLayout vk_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + EXIT_NOT_IMPLEMENTED(levels >= 16); + + uint32_t mip_width = width; + uint32_t mip_height = height; + + Vector regions(levels); + + if (objects.Size() == 1 && objects.At(0).type == GpuMemoryObjectType::StorageTexture) + { + auto* src_obj = static_cast(objects.At(0).obj); + + for (uint32_t i = 0; i < levels; i++) + { + auto mipmap_offset = UtilCalcMipmapOffset(i, width, height); + + regions[i].src_image = src_obj; + 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; + + if (mip_width > 1) + { + mip_width /= 2; + } + if (mip_height > 1) + { + mip_height /= 2; + } + } + } else + { + EXIT_NOT_IMPLEMENTED(levels != objects.Size()); + + for (uint32_t i = 0; i < levels; i++) + { + const auto& object = objects.At(i); + + EXIT_NOT_IMPLEMENTED(object.type != GpuMemoryObjectType::RenderTexture); + + auto* src_obj = static_cast(object.obj); + + regions[i].src_image = src_obj; + 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; + } + } + } + + UtilFillImage(ctx, 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, + VulkanMemory* mem) { KYTY_PROFILER_BLOCK("TextureObject::Create"); EXIT_IF(size == nullptr || vaddr == nullptr); EXIT_IF(mem == nullptr); EXIT_IF(ctx == nullptr); + EXIT_IF(params == nullptr); - auto dfmt = params[PARAM_DFMT_NFMT] >> 32u; - auto nfmt = params[PARAM_DFMT_NFMT] & 0xffffffffu; - auto width = params[PARAM_WIDTH_HEIGHT] >> 32u; - auto height = params[PARAM_WIDTH_HEIGHT] & 0xffffffffu; - auto levels = params[PARAM_LEVELS]; - auto swizzle = params[PARAM_SWIZZLE]; - auto usage = params[PARAM_USAGE]; + 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]; - VkImageUsageFlags vk_usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; - - switch (usage) - { - case TEXTURE_USAGE_SAMPLED: vk_usage |= VK_IMAGE_USAGE_SAMPLED_BIT; break; - case TEXTURE_USAGE_STORAGE: vk_usage |= VK_IMAGE_USAGE_STORAGE_BIT; break; - default: EXIT("unknown usage: %u\n", static_cast(usage)); - } + VkImageUsageFlags vk_usage = get_usage(); VkComponentMapping components {}; @@ -194,7 +367,7 @@ void* TextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const ui vk_obj->memory = *mem; - GetUpdateFunc()(ctx, params, vk_obj, vaddr, size, vaddr_num); + update_func(ctx, params, vk_obj, vaddr, size, vaddr_num); VkImageViewCreateInfo create_info {}; create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -208,7 +381,7 @@ void* TextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const ui create_info.subresourceRange.baseArrayLayer = 0; create_info.subresourceRange.baseMipLevel = 0; create_info.subresourceRange.layerCount = 1; - create_info.subresourceRange.levelCount = 1; + create_info.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; vkCreateImageView(ctx->device, &create_info, nullptr, &vk_obj->image_view); @@ -217,96 +390,110 @@ void* TextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const ui return vk_obj; } -static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +static void* create2_func(GraphicContext* ctx, const uint64_t* params, const Vector& objects, VulkanMemory* mem) { - KYTY_PROFILER_BLOCK("TextureObject::update_func"); + KYTY_PROFILER_BLOCK("TextureObject::CreateFromObjects"); - EXIT_IF(obj == nullptr); + EXIT_IF(objects.IsEmpty()); + EXIT_IF(mem == nullptr); EXIT_IF(ctx == nullptr); EXIT_IF(params == nullptr); - EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); - auto* vk_obj = static_cast(obj); + 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 tile = params[TextureObject::PARAM_TILE]; - 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 pitch = params[TextureObject::PARAM_PITCH]; - auto usage = params[TextureObject::PARAM_USAGE]; - bool neo = Config::IsNeo(); + VkImageUsageFlags vk_usage = get_usage(); - VkImageLayout vk_layout = VK_IMAGE_LAYOUT_UNDEFINED; + VkComponentMapping components {}; - switch (usage) + components.r = get_swizzle(swizzle & 0xffu); + components.g = get_swizzle((swizzle >> 8u) & 0xffu); + components.b = get_swizzle((swizzle >> 16u) & 0xffu); + components.a = get_swizzle((swizzle >> 24u) & 0xffu); + + auto pixel_format = get_texture_format(dfmt, nfmt); + + EXIT_NOT_IMPLEMENTED(pixel_format == VK_FORMAT_UNDEFINED); + EXIT_NOT_IMPLEMENTED(width == 0); + EXIT_NOT_IMPLEMENTED(height == 0); + + auto* vk_obj = new TextureVulkanImage; + + 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 = width; + image_info.extent.height = height; + image_info.extent.depth = 1; + image_info.mipLevels = levels; + image_info.arrayLayers = 1; + image_info.format = pixel_format; + image_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_info.usage = vk_usage; + image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_info.samples = VK_SAMPLE_COUNT_1_BIT; + + if (!CheckSwizzle(ctx, &image_info, &components)) { - case TextureObject::TEXTURE_USAGE_SAMPLED: vk_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; break; - case TextureObject::TEXTURE_USAGE_STORAGE: vk_layout = VK_IMAGE_LAYOUT_GENERAL; break; - default: EXIT("unknown usage: %u\n", static_cast(usage)); + EXIT("swizzle is not supported"); } - EXIT_NOT_IMPLEMENTED(levels >= 16); - - EXIT_NOT_IMPLEMENTED(tile != 8 && tile != 13); - - uint32_t level_sizes[16]; - - TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, nullptr, level_sizes, nullptr, nullptr); - - // dbg_test_mipmaps(ctx, VK_FORMAT_BC3_SRGB_BLOCK, 512, 512); - - uint32_t offset = 0; - uint32_t mip_width = width; - uint32_t mip_height = height; - uint32_t mip_pitch = pitch; - - Vector regions(levels); - for (uint32_t i = 0; i < levels; i++) + if (!CheckFormat(ctx, &image_info)) { - EXIT_NOT_IMPLEMENTED(level_sizes[i] == 0); - - regions[i].offset = offset; - regions[i].width = mip_width; - regions[i].height = mip_height; - regions[i].pitch = mip_pitch; - - offset += level_sizes[i]; - - if (mip_width > 1) - { - mip_width /= 2; - } - if (mip_height > 1) - { - mip_height /= 2; - } - if (mip_pitch > 1) - { - mip_pitch /= 2; - } + EXIT("format is not supported"); } - if (tile == 13) - { - EXIT_NOT_IMPLEMENTED(pitch != width); - auto* temp_buf = new uint8_t[*size]; - TileConvertTiledToLinear(temp_buf, reinterpret_cast(*vaddr), TileMode::TextureTiled, dfmt, nfmt, width, height, levels, neo); - UtilFillImage(ctx, vk_obj, temp_buf, *size, regions, static_cast(vk_layout)); - delete[] temp_buf; - } else if (tile == 8) - { - UtilFillImage(ctx, vk_obj, reinterpret_cast(*vaddr), *size, regions, static_cast(vk_layout)); - } -} + vk_obj->extent.width = width; + vk_obj->extent.height = height; + vk_obj->format = image_info.format; + vk_obj->image = nullptr; + vk_obj->image_view = nullptr; + vk_obj->layout = image_info.initialLayout; -bool TextureObject::Equal(const uint64_t* other) const -{ - return (params[PARAM_DFMT_NFMT] == other[PARAM_DFMT_NFMT] && params[PARAM_PITCH] == other[PARAM_PITCH] && - params[PARAM_WIDTH_HEIGHT] == other[PARAM_WIDTH_HEIGHT] && params[PARAM_USAGE] == other[PARAM_USAGE] && - params[PARAM_LEVELS] == other[PARAM_LEVELS] && params[PARAM_TILE] == other[PARAM_TILE] && - params[PARAM_NEO] == other[PARAM_NEO] && params[PARAM_SWIZZLE] == other[PARAM_SWIZZLE]); + 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; + + update2_func(ctx, params, vk_obj, 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 = components; + 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 = VK_REMAINING_MIP_LEVELS; + + 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) @@ -329,6 +516,24 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) delete vk_obj; } +bool TextureObject::Equal(const uint64_t* other) const +{ + return (params[PARAM_DFMT_NFMT] == other[PARAM_DFMT_NFMT] && params[PARAM_PITCH] == other[PARAM_PITCH] && + params[PARAM_WIDTH_HEIGHT] == other[PARAM_WIDTH_HEIGHT] && params[PARAM_LEVELS] == other[PARAM_LEVELS] && + params[PARAM_TILE] == other[PARAM_TILE] && params[PARAM_NEO] == other[PARAM_NEO] && + params[PARAM_SWIZZLE] == other[PARAM_SWIZZLE]); +} + +GpuObject::create_func_t TextureObject::GetCreateFunc() const +{ + return create_func; +} + +GpuObject::create_from_objects_func_t TextureObject::GetCreateFromObjectsFunc() const +{ + return create2_func; +} + GpuObject::delete_func_t TextureObject::GetDeleteFunc() const { return delete_func; diff --git a/source/emulator/src/Graphics/Objects/VertexBuffer.cpp b/source/emulator/src/Graphics/Objects/VertexBuffer.cpp index 5c7b6d8..9741282 100644 --- a/source/emulator/src/Graphics/Objects/VertexBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/VertexBuffer.cpp @@ -12,8 +12,8 @@ namespace Kyty::Libs::Graphics { -void* VertexBufferGpuObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, - VulkanMemory* mem) const +static void* create_func(GraphicContext* ctx, const uint64_t* /*params*/, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + VulkanMemory* mem) { KYTY_PROFILER_BLOCK("VertexBufferGpuObject::Create"); @@ -59,11 +59,6 @@ static void update_func(GraphicContext* /*ctx*/, const uint64_t* /*params*/, voi KYTY_NOT_IMPLEMENTED; } -bool VertexBufferGpuObject::Equal(const uint64_t* /*other*/) const -{ - return true; -} - static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* /*mem*/) { KYTY_PROFILER_BLOCK("VertexBufferGpuObject::delete_func"); @@ -79,6 +74,16 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* /*mem*/) delete vk_obj; } +bool VertexBufferGpuObject::Equal(const uint64_t* /*other*/) const +{ + return true; +} + +GpuObject::create_func_t VertexBufferGpuObject::GetCreateFunc() const +{ + return create_func; +} + GpuObject::delete_func_t VertexBufferGpuObject::GetDeleteFunc() const { return delete_func; diff --git a/source/emulator/src/Graphics/Objects/VideoOutBuffer.cpp b/source/emulator/src/Graphics/Objects/VideoOutBuffer.cpp index 1ef95ea..3df4884 100644 --- a/source/emulator/src/Graphics/Objects/VideoOutBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/VideoOutBuffer.cpp @@ -14,7 +14,58 @@ namespace Kyty::Libs::Graphics { -void* VideoOutBufferObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const +static bool buffer_is_tiled(uint64_t vaddr, uint64_t size) +{ + if ((size & 0x7u) == 0) + { + const auto* ptr = reinterpret_cast(vaddr); + const auto* ptr_end = reinterpret_cast(vaddr + size / 8); + for (uint64_t element = *ptr; ptr < ptr_end; ptr++) + { + if (element != *ptr) + { + return true; + } + } + return false; + } + return true; +} + +static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + KYTY_PROFILER_BLOCK("VideoOutBufferObject::update_func"); + + EXIT_IF(obj == nullptr); + EXIT_IF(ctx == nullptr); + EXIT_IF(params == nullptr); + EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); + + auto* vk_obj = static_cast(obj); + + bool tiled = (params[VideoOutBufferObject::PARAM_TILED] != 0); + bool neo = (params[VideoOutBufferObject::PARAM_NEO] != 0); + auto pitch = params[VideoOutBufferObject::PARAM_PITCH]; + auto width = params[VideoOutBufferObject::PARAM_WIDTH]; + auto height = params[VideoOutBufferObject::PARAM_HEIGHT]; + + vk_obj->layout = VK_IMAGE_LAYOUT_UNDEFINED; + + if (tiled && buffer_is_tiled(*vaddr, *size)) + { + EXIT_NOT_IMPLEMENTED(width != pitch); + auto* temp_buf = new uint8_t[*size]; + TileConvertTiledToLinear(temp_buf, reinterpret_cast(*vaddr), TileMode::VideoOutTiled, width, height, neo); + UtilFillImage(ctx, vk_obj, temp_buf, *size, pitch); + delete[] temp_buf; + } else + { + UtilFillImage(ctx, vk_obj, reinterpret_cast(*vaddr), *size, pitch); + } +} + +static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + VulkanMemory* mem) { KYTY_PROFILER_BLOCK("VideoOutBufferObject::Create"); @@ -22,9 +73,9 @@ void* VideoOutBufferObject::Create(GraphicContext* ctx, const uint64_t* vaddr, c EXIT_IF(mem == nullptr); EXIT_IF(ctx == nullptr); - auto pixel_format = params[PARAM_FORMAT]; - auto width = params[PARAM_WIDTH]; - auto height = params[PARAM_HEIGHT]; + auto pixel_format = params[VideoOutBufferObject::PARAM_FORMAT]; + auto width = params[VideoOutBufferObject::PARAM_WIDTH]; + auto height = params[VideoOutBufferObject::PARAM_HEIGHT]; EXIT_NOT_IMPLEMENTED(pixel_format != 0x80000000); EXIT_NOT_IMPLEMENTED(width == 0); @@ -81,7 +132,7 @@ void* VideoOutBufferObject::Create(GraphicContext* ctx, const uint64_t* vaddr, c // EXIT_NOT_IMPLEMENTED(mem->requirements.size > *size); - GetUpdateFunc()(ctx, params, vk_obj, vaddr, size, vaddr_num); + update_func(ctx, params, vk_obj, vaddr, size, vaddr_num); VkImageViewCreateInfo create_info {}; create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -107,63 +158,6 @@ void* VideoOutBufferObject::Create(GraphicContext* ctx, const uint64_t* vaddr, c return vk_obj; } -static bool buffer_is_tiled(uint64_t vaddr, uint64_t size) -{ - if ((size & 0x7u) == 0) - { - const auto* ptr = reinterpret_cast(vaddr); - const auto* ptr_end = reinterpret_cast(vaddr + size / 8); - for (uint64_t element = *ptr; ptr < ptr_end; ptr++) - { - if (element != *ptr) - { - return true; - } - } - return false; - } - return true; -} - -static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num) -{ - KYTY_PROFILER_BLOCK("VideoOutBufferObject::update_func"); - - EXIT_IF(obj == nullptr); - EXIT_IF(ctx == nullptr); - EXIT_IF(params == nullptr); - EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num != 1); - - auto* vk_obj = static_cast(obj); - - bool tiled = (params[VideoOutBufferObject::PARAM_TILED] != 0); - bool neo = (params[VideoOutBufferObject::PARAM_NEO] != 0); - auto pitch = params[VideoOutBufferObject::PARAM_PITCH]; - auto width = params[VideoOutBufferObject::PARAM_WIDTH]; - auto height = params[VideoOutBufferObject::PARAM_HEIGHT]; - - vk_obj->layout = VK_IMAGE_LAYOUT_UNDEFINED; - - if (tiled && buffer_is_tiled(*vaddr, *size)) - { - EXIT_NOT_IMPLEMENTED(width != pitch); - auto* temp_buf = new uint8_t[*size]; - TileConvertTiledToLinear(temp_buf, reinterpret_cast(*vaddr), TileMode::VideoOutTiled, width, height, neo); - UtilFillImage(ctx, vk_obj, temp_buf, *size, pitch); - delete[] temp_buf; - } else - { - UtilFillImage(ctx, vk_obj, reinterpret_cast(*vaddr), *size, pitch); - } -} - -bool VideoOutBufferObject::Equal(const uint64_t* other) const -{ - return (params[PARAM_FORMAT] == other[PARAM_FORMAT] && params[PARAM_WIDTH] == other[PARAM_WIDTH] && - params[PARAM_HEIGHT] == other[PARAM_HEIGHT] && params[PARAM_TILED] == other[PARAM_TILED] && - params[PARAM_PITCH] == other[PARAM_PITCH] && params[PARAM_NEO] == other[PARAM_NEO]); -} - static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) { KYTY_PROFILER_BLOCK("VideoOutBufferObject::delete_func"); @@ -187,6 +181,18 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) delete vk_obj; } +bool VideoOutBufferObject::Equal(const uint64_t* other) const +{ + return (params[PARAM_FORMAT] == other[PARAM_FORMAT] && params[PARAM_WIDTH] == other[PARAM_WIDTH] && + params[PARAM_HEIGHT] == other[PARAM_HEIGHT] && params[PARAM_TILED] == other[PARAM_TILED] && + params[PARAM_PITCH] == other[PARAM_PITCH] && params[PARAM_NEO] == other[PARAM_NEO]); +} + +GpuObject::create_func_t VideoOutBufferObject::GetCreateFunc() const +{ + return create_func; +} + GpuObject::delete_func_t VideoOutBufferObject::GetDeleteFunc() const { return delete_func; diff --git a/source/emulator/src/Graphics/Shader.cpp b/source/emulator/src/Graphics/Shader.cpp index 3567fba..c3479ce 100644 --- a/source/emulator/src/Graphics/Shader.cpp +++ b/source/emulator/src/Graphics/Shader.cpp @@ -215,6 +215,7 @@ static String dbg_fmt_to_str(const ShaderInstruction& inst) case ShaderInstructionFormat::Vdata3Vaddr3StSsDmask7: return U"Vdata4Vaddr3StSsDmask7"; break; case ShaderInstructionFormat::Vdata4Vaddr3StSsDmaskF: return U"Vdata4Vaddr3StSsDmaskF"; break; case ShaderInstructionFormat::Vdata4Vaddr3StDmaskF: return U"Vdata4Vaddr3StDmaskF"; break; + case ShaderInstructionFormat::Vdata4Vaddr4StDmaskF: return U"Vdata4Vaddr4StDmaskF"; break; case ShaderInstructionFormat::SVdstSVsrc0SVsrc1: return U"SVdstSVsrc0SVsrc1"; break; case ShaderInstructionFormat::VdstVsrc0Vsrc1Smask2: return U"VdstVsrc0Vsrc1Smask2"; break; case ShaderInstructionFormat::VdstVsrc0Vsrc1Vsrc2: return U"VdstVsrc0Vsrc1Vsrc2"; break; @@ -1554,6 +1555,17 @@ KYTY_SHADER_PARSER(shader_parse_mimg) inst.dst.size = 4; } break; + case 0x09: + inst.type = ShaderInstructionType::ImageStoreMip; + inst.src[0].size = 4; + inst.src[1].size = 8; + inst.src_num = 2; + if (dmask == 0xf) + { + inst.format = ShaderInstructionFormat::Vdata4Vaddr4StDmaskF; + inst.dst.size = 4; + } + break; case 0x20: inst.type = ShaderInstructionType::ImageSample; inst.src[0].size = 3; @@ -1572,6 +1584,12 @@ KYTY_SHADER_PARSER(shader_parse_mimg) default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown mimg opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); } + if (inst.format == ShaderInstructionFormat::Unknown) + { + printf("%s", dst->DbgDump().C_Str()); + EXIT("unknown mimg format for opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc) + } + dst->GetInstructions().Add(inst); return size; @@ -1857,10 +1875,10 @@ static void ps_check(const PsStageRegisters& ps) { EXIT_NOT_IMPLEMENTED(ps.target_output_mode[0] != 4 && ps.target_output_mode[0] != 9); EXIT_NOT_IMPLEMENTED(ps.conservative_z_export_value != 0x00000000); - EXIT_NOT_IMPLEMENTED(ps.shader_z_behavior != 0x00000001); + EXIT_NOT_IMPLEMENTED(ps.shader_z_behavior != 0x00000001 && ps.shader_z_behavior != 0x00000000); // EXIT_NOT_IMPLEMENTED(ps.shader_kill_enable != false); EXIT_NOT_IMPLEMENTED(ps.shader_z_export_enable != false); - EXIT_NOT_IMPLEMENTED(ps.shader_execute_on_noop != false); + // EXIT_NOT_IMPLEMENTED(ps.shader_execute_on_noop != false); // EXIT_NOT_IMPLEMENTED(ps.m_spiShaderPgmRsrc1Ps != 0x002c0000); // EXIT_NOT_IMPLEMENTED(ps.m_spiShaderPgmRsrc2Ps != 0x00000000); // EXIT_NOT_IMPLEMENTED(ps.vgprs != 0x00 && ps.vgprs != 0x01); @@ -2199,8 +2217,8 @@ static void ShaderGetStorageBuffer(ShaderStorageResources* info, int start_index info->buffers_num++; } -static void ShaderGetTextureBuffer(ShaderTextureResources* info, int start_index, int slot, const UserSgprInfo& user_sgpr, - const uint32_t* extended_buffer) +static void ShaderGetTextureBuffer(ShaderTextureResources* info, int start_index, int slot, ShaderTextureUsage usage, + const UserSgprInfo& user_sgpr, const uint32_t* extended_buffer) { EXIT_IF(info == nullptr); @@ -2216,6 +2234,7 @@ static void ShaderGetTextureBuffer(ShaderTextureResources* info, int start_index info->start_register[index] = start_index; info->extended[index] = extended; info->slots[index] = slot; + info->usages[index] = usage; if (!extended) { @@ -2302,7 +2321,7 @@ static void ShaderGetGdsPointer(ShaderGdsResources* info, int start_index, int s info->pointers_num++; } -static void ShaderCalcBindingIndices(ShaderBindResources* bind) +void ShaderCalcBindingIndices(ShaderBindResources* bind) { int binding_index = 0; @@ -2310,30 +2329,28 @@ static void ShaderCalcBindingIndices(ShaderBindResources* bind) if (bind->storage_buffers.buffers_num > 0) { - bind->storage_buffers.binding_index = binding_index; + bind->storage_buffers.binding_index = binding_index++; bind->push_constant_size += bind->storage_buffers.buffers_num * 16; - binding_index++; } if (bind->textures2D.textures_num > 0) { - bind->textures2D.binding_index = binding_index; + bind->textures2D.binding_sampled_index = binding_index++; + bind->textures2D.binding_storage_index = binding_index++; + bind->push_constant_size += bind->textures2D.textures_num * 32; - binding_index++; } if (bind->samplers.samplers_num > 0) { - bind->samplers.binding_index = binding_index; + bind->samplers.binding_index = binding_index++; bind->push_constant_size += bind->samplers.samplers_num * 16; - binding_index++; } if (bind->gds_pointers.pointers_num > 0) { - bind->gds_pointers.binding_index = binding_index; + bind->gds_pointers.binding_index = binding_index++; bind->push_constant_size += (((bind->gds_pointers.pointers_num - 1) / 4) + 1) * 16; - binding_index++; } EXIT_IF((bind->push_constant_size % 16) != 0); @@ -2411,6 +2428,7 @@ void ShaderGetInputInfoVS(const VertexShaderInfo* regs, ShaderVertexInputInfo* i ShaderCalcBindingIndices(&info->bind); } +// NOLINTNEXTLINE(readability-function-cognitive-complexity) void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputInfo* vs_info, ShaderPixelInputInfo* ps_info) { EXIT_IF(vs_info == nullptr); @@ -2420,6 +2438,8 @@ void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputIn 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; + ps_info->ps_early_z = (regs->ps_regs.shader_z_behavior == 1); + ps_info->ps_execute_on_noop = regs->ps_regs.shader_execute_on_noop; for (uint32_t i = 0; i < ps_info->input_num; i++) { @@ -2454,8 +2474,8 @@ void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputIn regs->ps_user_sgpr, extended_buffer); } else if (usage.flags == 3) { - ShaderGetTextureBuffer(&ps_info->bind.textures2D, usage.start_register, usage.slot, regs->ps_user_sgpr, - extended_buffer); + ShaderGetTextureBuffer(&ps_info->bind.textures2D, usage.start_register, usage.slot, ShaderTextureUsage::ReadOnly, + regs->ps_user_sgpr, extended_buffer); EXIT_NOT_IMPLEMENTED(ps_info->bind.textures2D.textures[ps_info->bind.textures2D.textures_num - 1].Type() != 9); } break; @@ -2468,6 +2488,15 @@ void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputIn ShaderGetStorageBuffer(&ps_info->bind.storage_buffers, usage.start_register, usage.slot, ShaderStorageUsage::Constant, regs->ps_user_sgpr, extended_buffer); break; + case 0x04: + EXIT_NOT_IMPLEMENTED(usage.flags != 3); + if (usage.flags == 3) + { + ShaderGetTextureBuffer(&ps_info->bind.textures2D, usage.start_register, usage.slot, ShaderTextureUsage::ReadWrite, + regs->ps_user_sgpr, extended_buffer); + EXIT_NOT_IMPLEMENTED(ps_info->bind.textures2D.textures[ps_info->bind.textures2D.textures_num - 1].Type() != 9); + } + break; case 0x1b: EXIT_NOT_IMPLEMENTED(usage.flags != 0); EXIT_NOT_IMPLEMENTED(usage.slot != 1); @@ -2524,7 +2553,8 @@ void ShaderGetInputInfoCS(const ComputeShaderInfo* regs, ShaderComputeInputInfo* regs->cs_user_sgpr, extended_buffer); } else if (usage.flags == 3) { - ShaderGetTextureBuffer(&info->bind.textures2D, usage.start_register, usage.slot, regs->cs_user_sgpr, extended_buffer); + ShaderGetTextureBuffer(&info->bind.textures2D, usage.start_register, usage.slot, ShaderTextureUsage::ReadOnly, + regs->cs_user_sgpr, extended_buffer); EXIT_NOT_IMPLEMENTED(info->bind.textures2D.textures[info->bind.textures2D.textures_num - 1].Type() != 9); } break; @@ -2562,21 +2592,22 @@ void ShaderGetInputInfoCS(const ComputeShaderInfo* regs, ShaderComputeInputInfo* static void ShaderDbgDumpResources(const ShaderBindResources& bind) { - printf("\t descriptor_set_slot = %u\n", bind.descriptor_set_slot); - printf("\t push_constant_offset = %u\n", bind.push_constant_offset); - printf("\t push_constant_size = %u\n", bind.push_constant_size); - printf("\t storage_buffers.buffers_num = %d\n", bind.storage_buffers.buffers_num); - printf("\t storage_buffers.binding_index = %d\n", bind.storage_buffers.binding_index); - printf("\t textures.textures_num = %d\n", bind.textures2D.textures_num); - printf("\t textures.binding_index = %d\n", bind.textures2D.binding_index); - printf("\t samplers.samplers_num = %d\n", bind.samplers.samplers_num); - printf("\t samplers.binding_index = %d\n", bind.samplers.binding_index); - printf("\t gds_pointers.pointers_num = %d\n", bind.gds_pointers.pointers_num); - printf("\t gds_pointers.binding_index = %d\n", bind.gds_pointers.binding_index); - printf("\t extended.used = %s\n", (bind.extended.used ? "true" : "false")); - printf("\t extended.slot = %d\n", bind.extended.slot); - printf("\t extended.start_register = %d\n", bind.extended.start_register); - printf("\t extended.data.Base = %" PRIx64 "\n", bind.extended.data.Base()); + printf("\t descriptor_set_slot = %u\n", bind.descriptor_set_slot); + printf("\t push_constant_offset = %u\n", bind.push_constant_offset); + printf("\t push_constant_size = %u\n", bind.push_constant_size); + printf("\t storage_buffers.buffers_num = %d\n", bind.storage_buffers.buffers_num); + printf("\t storage_buffers.binding_index = %d\n", bind.storage_buffers.binding_index); + printf("\t textures.textures_num = %d\n", bind.textures2D.textures_num); + printf("\t textures.binding_sampled_index = %d\n", bind.textures2D.binding_sampled_index); + printf("\t textures.binding_storage_index = %d\n", bind.textures2D.binding_storage_index); + printf("\t samplers.samplers_num = %d\n", bind.samplers.samplers_num); + printf("\t samplers.binding_index = %d\n", bind.samplers.binding_index); + printf("\t gds_pointers.pointers_num = %d\n", bind.gds_pointers.pointers_num); + printf("\t gds_pointers.binding_index = %d\n", bind.gds_pointers.binding_index); + printf("\t extended.used = %s\n", (bind.extended.used ? "true" : "false")); + printf("\t extended.slot = %d\n", bind.extended.slot); + printf("\t extended.start_register = %d\n", bind.extended.start_register); + printf("\t extended.data.Base = %" PRIx64 "\n", bind.extended.data.Base()); for (int i = 0; i < bind.storage_buffers.buffers_num; i++) { @@ -2640,6 +2671,7 @@ static void ShaderDbgDumpResources(const ShaderBindResources& bind) printf("\t\t slot = %d\n", bind.textures2D.slots[i]); printf("\t\t start_register = %d\n", bind.textures2D.start_register[i]); printf("\t\t extended = %s\n", (bind.textures2D.extended[i] ? "true" : "false")); + printf("\t\t usage = %s\n", Core::EnumName(bind.textures2D.usages[i]).C_Str()); } for (int i = 0; i < bind.samplers.samplers_num; i++) @@ -2754,6 +2786,8 @@ void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo* info) printf("\t input_num = %u\n", info->input_num); printf("\t ps_pos_xy = %s\n", info->ps_pos_xy ? "true" : "false"); printf("\t ps_pixel_kill_enable = %s\n", info->ps_pixel_kill_enable ? "true" : "false"); + printf("\t ps_early_z = %s\n", info->ps_early_z ? "true" : "false"); + printf("\t ps_execute_on_noop = %s\n", info->ps_execute_on_noop ? "true" : "false"); for (uint32_t i = 0; i < info->input_num; i++) { @@ -3140,17 +3174,92 @@ Vector ShaderRecompileCS(const ShaderCode& code, const ShaderComputeIn return ret; } +// NOLINTNEXTLINE(readability-function-cognitive-complexity) static ShaderBindParameters ShaderUpdateBindInfo(const ShaderCode& code, const ShaderBindResources* bind) { ShaderBindParameters p {}; + + auto find_image_op = [&](int index, int s, bool& found, bool& without_sampler) + { + const auto& insts = code.GetInstructions(); + int size = static_cast(insts.Size()); + for (int i = index; i < size; i++) + { + const auto& inst = insts.At(i); + + if ((inst.dst.type == ShaderOperandType::Sgpr && s >= inst.dst.register_id && s < inst.dst.register_id + inst.dst.size) || + (inst.dst2.type == ShaderOperandType::Sgpr && s >= inst.dst2.register_id && s < inst.dst2.register_id + inst.dst2.size) || + inst.type == ShaderInstructionType::SEndpgm) + { + break; + } + + if (inst.type == ShaderInstructionType::ImageStoreMip || inst.type == ShaderInstructionType::ImageLoad) + { + if (inst.src[1].register_id == s) + { + EXIT_NOT_IMPLEMENTED(found && !without_sampler); + without_sampler = true; + found = true; + } + } else if (inst.type == ShaderInstructionType::ImageSample) + { + if (inst.src[1].register_id == s) + { + EXIT_NOT_IMPLEMENTED(found && without_sampler); + without_sampler = false; + found = true; + } + } + } + }; + if (bind->textures2D.textures_num > 0) { - bool image_sample = code.HasAnyOf({ShaderInstructionType::ImageSample}); - bool image_load = code.HasAnyOf({ShaderInstructionType::ImageLoad}); + const auto& insts = code.GetInstructions(); - EXIT_NOT_IMPLEMENTED(image_sample && image_load); + for (int ti = 0; ti < bind->textures2D.textures_num; ti++) + { + bool found = false; + if (bind->textures2D.extended[ti]) + { + int s = bind->extended.start_register; - p.textures2D_without_sampler = image_load; + int index = 0; + for (const auto& inst: insts) + { + if ((inst.dst.type == ShaderOperandType::Sgpr && s >= inst.dst.register_id && + s < inst.dst.register_id + inst.dst.size) || + (inst.dst2.type == ShaderOperandType::Sgpr && s >= inst.dst2.register_id && + s < inst.dst2.register_id + inst.dst2.size) || + inst.type == ShaderInstructionType::SEndpgm) + { + break; + } + + if (inst.type == ShaderInstructionType::SLoadDwordx8 && inst.src[0].register_id == s && + static_cast(inst.src[1].constant.u >> 2u) + 16 == bind->textures2D.start_register[ti]) + { + find_image_op(index + 1, inst.dst.register_id, found, p.textures2d_without_sampler[ti]); + } + + index++; + } + } else + { + find_image_op(0, bind->textures2D.start_register[ti], found, p.textures2d_without_sampler[ti]); + } + + EXIT_NOT_IMPLEMENTED(!found); + + if (p.textures2d_without_sampler[ti]) + { + p.textures2d_storage_num++; + } else + { + p.textures2d_sampled_num++; + } + } } return p; } @@ -3176,16 +3285,16 @@ static void ShaderGetBindIds(ShaderId* ret, const ShaderBindResources& bind) for (int i = 0; i < bind.storage_buffers.buffers_num; i++) { - const auto& r = bind.storage_buffers.buffers[i]; + // const auto& r = bind.storage_buffers.buffers[i]; - ret->ids.Add(static_cast(r.SwizzleEnabled())); - ret->ids.Add(r.DstSelX()); - ret->ids.Add(r.DstSelY()); - ret->ids.Add(r.DstSelZ()); - ret->ids.Add(r.DstSelW()); - ret->ids.Add(r.Nfmt()); - ret->ids.Add(r.Dfmt()); - ret->ids.Add(static_cast(r.AddTid())); + // ret->ids.Add(static_cast(r.SwizzleEnabled())); + // ret->ids.Add(r.DstSelX()); + // ret->ids.Add(r.DstSelY()); + // ret->ids.Add(r.DstSelZ()); + // ret->ids.Add(r.DstSelW()); + // ret->ids.Add(r.Nfmt()); + // ret->ids.Add(r.Dfmt()); + // ret->ids.Add(static_cast(r.AddTid())); ret->ids.Add(bind.storage_buffers.slots[i]); ret->ids.Add(bind.storage_buffers.start_register[i]); ret->ids.Add(static_cast(bind.storage_buffers.extended[i])); @@ -3196,66 +3305,67 @@ static void ShaderGetBindIds(ShaderId* ret, const ShaderBindResources& bind) for (int i = 0; i < bind.textures2D.textures_num; i++) { - const auto& r = bind.textures2D.textures[i]; - ret->ids.Add(r.MinLod()); - ret->ids.Add(r.Dfmt()); - ret->ids.Add(r.Nfmt()); - ret->ids.Add(r.Width()); - ret->ids.Add(r.Height()); - ret->ids.Add(r.PerfMod()); - ret->ids.Add(static_cast(r.Interlaced())); - ret->ids.Add(r.DstSelX()); - ret->ids.Add(r.DstSelY()); - ret->ids.Add(r.DstSelZ()); - ret->ids.Add(r.DstSelW()); - ret->ids.Add(r.BaseLevel()); - ret->ids.Add(r.LastLevel()); - ret->ids.Add(r.TilingIdx()); - ret->ids.Add(static_cast(r.Pow2Pad())); - ret->ids.Add(r.Type()); - ret->ids.Add(r.Depth()); - ret->ids.Add(r.Pitch()); - ret->ids.Add(r.BaseArray()); - ret->ids.Add(r.LastArray()); - ret->ids.Add(r.MinLodWarn()); - ret->ids.Add(r.CounterBankId()); - ret->ids.Add(static_cast(r.LodHdwCntEn())); + // const auto& r = bind.textures2D.textures[i]; + // ret->ids.Add(r.MinLod()); + // ret->ids.Add(r.Dfmt()); + // ret->ids.Add(r.Nfmt()); + // ret->ids.Add(r.Width()); + // ret->ids.Add(r.Height()); + // ret->ids.Add(r.PerfMod()); + // ret->ids.Add(static_cast(r.Interlaced())); + // ret->ids.Add(r.DstSelX()); + // ret->ids.Add(r.DstSelY()); + // ret->ids.Add(r.DstSelZ()); + // ret->ids.Add(r.DstSelW()); + // ret->ids.Add(r.BaseLevel()); + // ret->ids.Add(r.LastLevel()); + // ret->ids.Add(r.TilingIdx()); + // ret->ids.Add(static_cast(r.Pow2Pad())); + // ret->ids.Add(r.Type()); + // ret->ids.Add(r.Depth()); + // ret->ids.Add(r.Pitch()); + // ret->ids.Add(r.BaseArray()); + // ret->ids.Add(r.LastArray()); + // ret->ids.Add(r.MinLodWarn()); + // ret->ids.Add(r.CounterBankId()); + // ret->ids.Add(static_cast(r.LodHdwCntEn())); ret->ids.Add(bind.textures2D.slots[i]); ret->ids.Add(bind.textures2D.start_register[i]); ret->ids.Add(static_cast(bind.textures2D.extended[i])); + ret->ids.Add(static_cast(bind.textures2D.usages[i])); } ret->ids.Add(bind.samplers.samplers_num); for (int i = 0; i < bind.samplers.samplers_num; i++) { - const auto& r = bind.samplers.samplers[i]; + // const auto& r = bind.samplers.samplers[i]; - ret->ids.Add(r.ClampX()); - ret->ids.Add(r.ClampY()); - ret->ids.Add(r.ClampZ()); - ret->ids.Add(r.MaxAnisoRatio()); - ret->ids.Add(r.DepthCompareFunc()); - ret->ids.Add(static_cast(r.ForceUnormCoords())); - ret->ids.Add(r.AnisoThreshold()); - ret->ids.Add(static_cast(r.McCoordTrunc())); - ret->ids.Add(static_cast(r.ForceDegamma())); - ret->ids.Add(r.AnisoBias()); - ret->ids.Add(static_cast(r.TruncCoord())); - ret->ids.Add(static_cast(r.DisableCubeWrap())); - ret->ids.Add(r.FilterMode()); - ret->ids.Add(r.MinLod()); - ret->ids.Add(r.MaxLod()); - ret->ids.Add(r.PerfMip()); - ret->ids.Add(r.PerfZ()); - ret->ids.Add(r.LodBias()); - ret->ids.Add(r.LodBiasSec()); - ret->ids.Add(r.XyMagFilter()); - ret->ids.Add(r.XyMinFilter()); - ret->ids.Add(r.ZFilter()); - ret->ids.Add(r.MipFilter()); - ret->ids.Add(r.BorderColorPtr()); - ret->ids.Add(r.BorderColorType()); + // ret->ids.Add(r.ClampX()); + // ret->ids.Add(r.ClampY()); + // ret->ids.Add(r.ClampZ()); + // ret->ids.Add(r.MaxAnisoRatio()); + // ret->ids.Add(r.DepthCompareFunc()); + // ret->ids.Add(static_cast(r.ForceUnormCoords())); + // ret->ids.Add(r.AnisoThreshold()); + // ret->ids.Add(static_cast(r.McCoordTrunc())); + // ret->ids.Add(static_cast(r.ForceDegamma())); + // ret->ids.Add(r.AnisoBias()); + // ret->ids.Add(static_cast(r.TruncCoord())); + // ret->ids.Add(static_cast(r.DisableCubeWrap())); + // ret->ids.Add(r.FilterMode()); + // ret->ids.Add(r.MinLod()); + // ret->ids.Add(r.MaxLod()); + // ret->ids.Add(r.PerfMip()); + // ret->ids.Add(r.PerfZ()); + // ret->ids.Add(r.LodBias()); + // ret->ids.Add(r.LodBiasSec()); + // ret->ids.Add(r.XyMagFilter()); + // ret->ids.Add(r.XyMinFilter()); + // ret->ids.Add(r.ZFilter()); + // ret->ids.Add(r.MipFilter()); + // ret->ids.Add(r.BorderColorPtr()); + // ret->ids.Add(r.BorderColorType()); ret->ids.Add(bind.samplers.slots[i]); ret->ids.Add(bind.samplers.start_register[i]); ret->ids.Add(static_cast(bind.samplers.extended[i])); @@ -3360,6 +3470,8 @@ ShaderId ShaderGetIdPS(const PixelShaderInfo* regs, const ShaderPixelInputInfo* ret.ids.Add(input_info->input_num); ret.ids.Add(static_cast(input_info->ps_pos_xy)); ret.ids.Add(static_cast(input_info->ps_pixel_kill_enable)); + ret.ids.Add(static_cast(input_info->ps_early_z)); + ret.ids.Add(static_cast(input_info->ps_execute_on_noop)); for (uint32_t i = 0; i < input_info->input_num; i++) { diff --git a/source/emulator/src/Graphics/ShaderSpirv.cpp b/source/emulator/src/Graphics/ShaderSpirv.cpp index 3288bef..58403cc 100644 --- a/source/emulator/src/Graphics/ShaderSpirv.cpp +++ b/source/emulator/src/Graphics/ShaderSpirv.cpp @@ -183,6 +183,85 @@ constexpr char32_t FUNC_ADDC[] = UR"( OpFunctionEnd )"; +constexpr char32_t FUNC_MIPMAP[] = UR"( + ; uvec2 mipmap(uint lod, uint width, uint height) + ; { + ; uint mip_width = width; + ; uint mip_height = height; + ; uint mip_x = 0; + ; uint mip_y = 0; + ; for (uint i = 0; i < 16; i++) + ; { + ; if (i == lod) + ; { + ; return uvec2(mip_x, mip_y); + ; } + ; bool odd = ((i & 1u) != 0u); + ; mip_x += (odd ? mip_width : 0u); + ; mip_y += (odd ? 0u : mip_height); + ; mip_width >>= (mip_width > 1u ? 1u : 0u); + ; mip_height >>= (mip_height > 1u ? 1u : 0u); + ; } + ; return uvec2(mip_x, mip_y); + ; } + %mipmap = OpFunction %v2uint None %function_u2_u_u_u + %mipmap_33 = OpFunctionParameter %uint + %mipmap_16 = OpFunctionParameter %uint + %mipmap_18 = OpFunctionParameter %uint + %mipmap_14 = OpLabel + OpSelectionMerge %mipmap_188 None + OpSwitch %uint_0 %mipmap_191 + %mipmap_191 = OpLabel + OpBranch %mipmap_23 + %mipmap_23 = OpLabel + %mipmap_296 = OpPhi %uint %uint_0 %mipmap_191 %mipmap_56 %mipmap_26 + %mipmap_295 = OpPhi %uint %mipmap_18 %mipmap_191 %mipmap_66 %mipmap_26 + %mipmap_294 = OpPhi %uint %uint_0 %mipmap_191 %mipmap_51 %mipmap_26 + %mipmap_293 = OpPhi %uint %mipmap_16 %mipmap_191 %mipmap_61 %mipmap_26 + %mipmap_292 = OpPhi %uint %uint_0 %mipmap_191 %mipmap_70 %mipmap_26 + OpLoopMerge %mipmap_25 %mipmap_26 None + OpBranch %mipmap_27 + %mipmap_27 = OpLabel + %mipmap_31 = OpULessThan %bool %mipmap_292 %uint_16 + OpBranchConditional %mipmap_31 %mipmap_24 %mipmap_25 + %mipmap_24 = OpLabel + %mipmap_34 = OpIEqual %bool %mipmap_292 %mipmap_33 + OpSelectionMerge %mipmap_36 None + OpBranchConditional %mipmap_34 %mipmap_35 %mipmap_36 + %mipmap_35 = OpLabel + %mipmap_39 = OpCompositeConstruct %v2uint %mipmap_294 %mipmap_296 + OpBranch %mipmap_25 + %mipmap_36 = OpLabel + %mipmap_45 = OpBitwiseAnd %uint %mipmap_292 %uint_1 + %mipmap_46 = OpINotEqual %bool %mipmap_45 %uint_0 + %mipmap_49 = OpSelect %uint %mipmap_46 %mipmap_293 %uint_0 + %mipmap_51 = OpIAdd %uint %mipmap_294 %mipmap_49 + %mipmap_54 = OpSelect %uint %mipmap_46 %uint_0 %mipmap_295 + %mipmap_56 = OpIAdd %uint %mipmap_296 %mipmap_54 + %mipmap_58 = OpUGreaterThan %bool %mipmap_293 %uint_1 + %mipmap_59 = OpSelect %uint %mipmap_58 %uint_1 %uint_0 + %mipmap_61 = OpShiftRightLogical %uint %mipmap_293 %mipmap_59 + %mipmap_63 = OpUGreaterThan %bool %mipmap_295 %uint_1 + %mipmap_64 = OpSelect %uint %mipmap_63 %uint_1 %uint_0 + %mipmap_66 = OpShiftRightLogical %uint %mipmap_295 %mipmap_64 + OpBranch %mipmap_26 + %mipmap_26 = OpLabel + %mipmap_70 = OpIAdd %uint %mipmap_292 %int_1 + OpBranch %mipmap_23 + %mipmap_25 = OpLabel + %mipmap_302 = OpPhi %v2uint %undef_v2uint %mipmap_27 %mipmap_39 %mipmap_35 + %mipmap_297 = OpPhi %bool %false %mipmap_27 %true %mipmap_35 + OpSelectionMerge %mipmap_195 None + OpBranchConditional %mipmap_297 %mipmap_188 %mipmap_195 + %mipmap_195 = OpLabel + %mipmap_73 = OpCompositeConstruct %v2uint %mipmap_294 %mipmap_296 + OpBranch %mipmap_188 + %mipmap_188 = OpLabel + %mipmap_301 = OpPhi %v2uint %mipmap_302 %mipmap_25 %mipmap_73 %mipmap_195 + OpReturnValue %mipmap_301 + OpFunctionEnd +)"; + constexpr char32_t FUNC_ORDERED[] = UR"( ; bool unordered(float f1, float f2) ; { @@ -1140,7 +1219,8 @@ public: void SetPsInputInfo(const ShaderPixelInputInfo* input_info) { m_ps_input_info = input_info; } [[nodiscard]] const ShaderPixelInputInfo* GetPsInputInfo() const { return m_ps_input_info; } - [[nodiscard]] const ShaderBindResources* GetBindInfo() const { return m_bind; } + [[nodiscard]] const ShaderBindResources* GetBindInfo() const { return m_bind; } + [[nodiscard]] const ShaderBindParameters& GetBindParams() const { return m_bind_params; } void AddConstantUint(uint32_t u); void AddConstantInt(int i); @@ -2103,10 +2183,11 @@ KYTY_RECOMPILER_FUNC(Recompile_Exp_Pos0Vsrc0Vsrc1Vsrc2Vsrc3Done) KYTY_RECOMPILER_FUNC(Recompile_ImageSample_Vdata3Vaddr3StSsDmask7) { - const auto& inst = code.GetInstructions().At(index); - const auto* bind_info = spirv->GetBindInfo(); + const auto& inst = code.GetInstructions().At(index); + const auto* bind_info = spirv->GetBindInfo(); + const auto& bind_params = spirv->GetBindParams(); - if (bind_info != nullptr && bind_info->textures2D.textures_num > 0 && bind_info->samplers.samplers_num > 0) + if (bind_info != nullptr && bind_params.textures2d_sampled_num > 0 && bind_info->samplers.samplers_num > 0) { auto dst_value0 = operand_variable_to_str(inst.dst, 0); auto dst_value1 = operand_variable_to_str(inst.dst, 1); @@ -2127,8 +2208,8 @@ KYTY_RECOMPILER_FUNC(Recompile_ImageSample_Vdata3Vaddr3StSsDmask7) static const char32_t* text = UR"( %t24_ = OpLoad %uint % - %t26_ = OpAccessChain %_ptr_UniformConstant_Image %textures2D %t24_ - %t27_ = OpLoad %Image %t26_ + %t26_ = OpAccessChain %_ptr_UniformConstant_ImageS %textures2D_S %t24_ + %t27_ = OpLoad %ImageS %t26_ %t33_ = OpLoad %uint % %t35_ = OpAccessChain %_ptr_UniformConstant_Sampler %samplers %t33_ %t36_ = OpLoad %Sampler %t35_ @@ -2167,10 +2248,11 @@ KYTY_RECOMPILER_FUNC(Recompile_ImageSample_Vdata3Vaddr3StSsDmask7) KYTY_RECOMPILER_FUNC(Recompile_ImageSample_Vdata4Vaddr3StSsDmaskF) { - const auto& inst = code.GetInstructions().At(index); - const auto* bind_info = spirv->GetBindInfo(); + const auto& inst = code.GetInstructions().At(index); + const auto* bind_info = spirv->GetBindInfo(); + const auto& bind_params = spirv->GetBindParams(); - if (bind_info != nullptr && bind_info->textures2D.textures_num > 0 && bind_info->samplers.samplers_num > 0) + if (bind_info != nullptr && bind_params.textures2d_sampled_num > 0 && bind_info->samplers.samplers_num > 0) { auto dst_value0 = operand_variable_to_str(inst.dst, 0); auto dst_value1 = operand_variable_to_str(inst.dst, 1); @@ -2192,8 +2274,8 @@ KYTY_RECOMPILER_FUNC(Recompile_ImageSample_Vdata4Vaddr3StSsDmaskF) static const char32_t* text = UR"( %t24_ = OpLoad %uint % - %t26_ = OpAccessChain %_ptr_UniformConstant_Image %textures2D %t24_ - %t27_ = OpLoad %Image %t26_ + %t26_ = OpAccessChain %_ptr_UniformConstant_ImageS %textures2D_S %t24_ + %t27_ = OpLoad %ImageS %t26_ %t33_ = OpLoad %uint % %t35_ = OpAccessChain %_ptr_UniformConstant_Sampler %samplers %t33_ %t36_ = OpLoad %Sampler %t35_ @@ -2236,10 +2318,11 @@ KYTY_RECOMPILER_FUNC(Recompile_ImageSample_Vdata4Vaddr3StSsDmaskF) KYTY_RECOMPILER_FUNC(Recompile_ImageLoad_Vdata4Vaddr3StDmaskF) { - const auto& inst = code.GetInstructions().At(index); - const auto* bind_info = spirv->GetBindInfo(); + const auto& inst = code.GetInstructions().At(index); + const auto* bind_info = spirv->GetBindInfo(); + const auto& bind_params = spirv->GetBindParams(); - if (bind_info != nullptr && bind_info->textures2D.textures_num > 0) + 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); @@ -2261,8 +2344,8 @@ KYTY_RECOMPILER_FUNC(Recompile_ImageLoad_Vdata4Vaddr3StDmaskF) static const char32_t* text = UR"( %t24_ = OpLoad %uint % - %t26_ = OpAccessChain %_ptr_UniformConstant_Image %textures2D %t24_ - %t27_ = OpLoad %Image %t26_ + %t26_ = OpAccessChain %_ptr_UniformConstant_ImageL %textures2D_L %t24_ + %t27_ = OpLoad %ImageL %t26_ %t67_ = OpLoad %float % %t69_ = OpBitcast %uint %t67_ %t70_ = OpLoad %float % @@ -2300,6 +2383,80 @@ KYTY_RECOMPILER_FUNC(Recompile_ImageLoad_Vdata4Vaddr3StDmaskF) return false; } +KYTY_RECOMPILER_FUNC(Recompile_ImageStoreMip_Vdata4Vaddr4StDmaskF) +{ + 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 src0_value2 = operand_variable_to_str(inst.src[0], 2); + + 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_ + %t701_ = OpLoad %float % + %t711_ = OpBitcast %uint %t701_ + %t160_ = OpFunctionCall %v2uint %mipmap %t711_ %t146_ %t151_ + %t73_ = OpCompositeConstruct %v2uint %t69_ %t71_ + %t84_ = OpLoad %float % + %t85_ = OpLoad %float % + %t86_ = OpLoad %float % + %t87_ = OpLoad %float % + %t172_ = OpIAdd %v2uint %t160_ %t73_ + %t88_ = OpCompositeConstruct %v4float %t84_ %t85_ %t86_ %t87_ + OpImageWrite %t27_ %t172_ %t88_ +)"; + *dst_source += String(text) + .ReplaceStr(U"", String::FromPrintf("%u", index)) + .ReplaceStr(U"", src0_value0.value) + .ReplaceStr(U"", src0_value1.value) + .ReplaceStr(U"", src0_value2.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; +} + /* XXX: Andn2, Or, Nor, Cselect */ KYTY_RECOMPILER_FUNC(Recompile_S_XXX_B64_Sdst2Ssrc02Ssrc12) { @@ -4533,6 +4690,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_ImageStoreMip_Vdata4Vaddr4StDmaskF, ShaderInstructionType::ImageStoreMip, ShaderInstructionFormat::Vdata4Vaddr4StDmaskF, {U""}}, {Recompile_SBufferLoadDword_SdstSvSoffset, ShaderInstructionType::SBufferLoadDword, ShaderInstructionFormat::SdstSvSoffset, {U""}}, {Recompile_SBufferLoadDwordx2_Sdst2SvSoffset, ShaderInstructionType::SBufferLoadDwordx2, ShaderInstructionFormat::Sdst2SvSoffset, {U""}}, @@ -4954,15 +5112,15 @@ void Spirv::WriteHeader() OpMemoryModel Logical GLSL450 OpEntryPoint %main "main" - + )"; String header_str; - String execution_mode; Core::StringList vars; Core::StringList extensions; Core::StringList imports; + Core::StringList execution_modes; imports.Add(U"%GLSL_std_450 = OpExtInstImport \"GLSL.std.450\""); @@ -4978,9 +5136,13 @@ void Spirv::WriteHeader() { vars.Add(U"%buf"); } - if (m_bind->textures2D.textures_num > 0) + if (m_bind_params.textures2d_sampled_num > 0) { - vars.Add(U"%textures2D"); + vars.Add(U"%textures2D_S"); + } + if (m_bind_params.textures2d_storage_num > 0) + { + vars.Add(U"%textures2D_L"); } if (m_bind->samplers.samplers_num > 0) { @@ -5010,9 +5172,13 @@ void Spirv::WriteHeader() { vars.Add(U"%gl_FragCoord"); } + if (m_ps_input_info->ps_early_z) + { + execution_modes.Add(U"OpExecutionMode %main EarlyFragmentTests\n"); + } } - header_str = String(header).ReplaceStr(U"", U"Fragment"); - execution_mode = U"OpExecutionMode %main OriginUpperLeft\n"; + header_str = String(header).ReplaceStr(U"", U"Fragment"); + execution_modes.Add(U"OpExecutionMode %main OriginUpperLeft\n"); // TODO() do we need PixelCenterInteger mode? break; case ShaderType::Vertex: @@ -5035,8 +5201,8 @@ void Spirv::WriteHeader() case ShaderType::Compute: if (m_cs_input_info != nullptr) { - execution_mode = String::FromPrintf("OpExecutionMode %%main LocalSize %u %u %u", m_cs_input_info->threads_num[0], - m_cs_input_info->threads_num[1], m_cs_input_info->threads_num[2]); + execution_modes.Add(String::FromPrintf("OpExecutionMode %%main LocalSize %u %u %u", m_cs_input_info->threads_num[0], + m_cs_input_info->threads_num[1], m_cs_input_info->threads_num[2])); } vars.Add(U"%gl_LocalInvocationID"); vars.Add(U"%gl_WorkGroupID"); @@ -5046,7 +5212,7 @@ void Spirv::WriteHeader() } m_source += header_str.ReplaceStr(U"", vars.Concat(U' ')) - .ReplaceStr(U"", execution_mode) + .ReplaceStr(U"", execution_modes.Concat(U"\n" + String(U' ', 15))) .ReplaceStr(U"", imports.Concat(U"\n" + String(U' ', 15))) .ReplaceStr(U"", extensions.Concat(U"\n" + String(U' ', 15))); } @@ -5136,9 +5302,14 @@ void Spirv::WriteAnnotations() OpDecorate %buf Binding )"; - static const char32_t* textures_annotations = UR"( - OpDecorate %textures2D DescriptorSet - OpDecorate %textures2D Binding + static const char32_t* textures_annotations_s = UR"( + OpDecorate %textures2D_S DescriptorSet + OpDecorate %textures2D_S Binding +)"; + + static const char32_t* textures_annotations_l = UR"( + OpDecorate %textures2D_L DescriptorSet + OpDecorate %textures2D_L Binding )"; static const char32_t* samplers_annotations = UR"( @@ -5169,11 +5340,17 @@ void Spirv::WriteAnnotations() .ReplaceStr(U"", String::FromPrintf("%u", m_bind->descriptor_set_slot)) .ReplaceStr(U"", String::FromPrintf("%d", m_bind->storage_buffers.binding_index)); } - if (m_bind->textures2D.textures_num > 0) + if (m_bind_params.textures2d_sampled_num > 0) { - m_source += String(textures_annotations) + m_source += String(textures_annotations_s) .ReplaceStr(U"", String::FromPrintf("%u", m_bind->descriptor_set_slot)) - .ReplaceStr(U"", String::FromPrintf("%d", m_bind->textures2D.binding_index)); + .ReplaceStr(U"", String::FromPrintf("%d", m_bind->textures2D.binding_sampled_index)); + } + if (m_bind_params.textures2d_storage_num > 0) + { + m_source += String(textures_annotations_l) + .ReplaceStr(U"", String::FromPrintf("%u", m_bind->descriptor_set_slot)) + .ReplaceStr(U"", String::FromPrintf("%d", m_bind->textures2D.binding_storage_index)); } if (m_bind->samplers.samplers_num > 0) { @@ -5210,6 +5387,8 @@ void Spirv::WriteTypes() %v4float = OpTypeVector %float 4 %v2uint = OpTypeVector %uint 2 %v3uint = OpTypeVector %uint 3 + %v4uint = OpTypeVector %uint 4 + %undef_v2uint = OpUndef %v2uint %_ptr_Input_int = OpTypePointer Input %int %_ptr_Input_uint = OpTypePointer Input %uint %_ptr_Input_float = OpTypePointer Input %float @@ -5286,20 +5465,20 @@ void Spirv::WriteTypes() )"; static const char32_t* textures_sampled_types = UR"( - %Image = OpTypeImage %float 2D 0 0 0 1 Unknown - %textures2D_uint_ = OpConstant %uint - %_arr_Image_uint_ = OpTypeArray %Image %textures2D_uint_ -%_ptr_UniformConstant__arr_Image_uint_ = OpTypePointer UniformConstant %_arr_Image_uint_ - %_ptr_UniformConstant_Image = OpTypePointer UniformConstant %Image - %SampledImage = OpTypeSampledImage %Image + %ImageS = OpTypeImage %float 2D 0 0 0 1 Unknown + %textures2D_S_uint_ = OpConstant %uint + %_arr_ImageS_uint_ = OpTypeArray %ImageS %textures2D_S_uint_ +%_ptr_UniformConstant__arr_ImageS_uint_ = OpTypePointer UniformConstant %_arr_ImageS_uint_ + %_ptr_UniformConstant_ImageS = OpTypePointer UniformConstant %ImageS + %SampledImage = OpTypeSampledImage %ImageS )"; static const char32_t* textures_loaded_types = UR"( - %Image = OpTypeImage %float 2D 0 0 0 2 Rgba8 - %textures2D_uint_ = OpConstant %uint - %_arr_Image_uint_ = OpTypeArray %Image %textures2D_uint_ -%_ptr_UniformConstant__arr_Image_uint_ = OpTypePointer UniformConstant %_arr_Image_uint_ - %_ptr_UniformConstant_Image = OpTypePointer UniformConstant %Image + %ImageL = OpTypeImage %float 2D 0 0 0 2 Rgba8 + %textures2D_L_uint_ = OpConstant %uint + %_arr_ImageL_uint_ = OpTypeArray %ImageL %textures2D_L_uint_ +%_ptr_UniformConstant__arr_ImageL_uint_ = OpTypePointer UniformConstant %_arr_ImageL_uint_ + %_ptr_UniformConstant_ImageL = OpTypePointer UniformConstant %ImageL )"; static const char32_t* samplers_types = UR"( @@ -5333,10 +5512,15 @@ void Spirv::WriteTypes() m_source += String(storage_buffers_types).ReplaceStr(U"", String::FromPrintf("%d", m_bind->storage_buffers.buffers_num)); } - if (m_bind->textures2D.textures_num > 0) + if (m_bind_params.textures2d_sampled_num > 0) { - m_source += String(m_bind_params.textures2D_without_sampler ? textures_loaded_types : textures_sampled_types) - .ReplaceStr(U"", String::FromPrintf("%d", m_bind->textures2D.textures_num)); + m_source += + String(textures_sampled_types).ReplaceStr(U"", String::FromPrintf("%d", m_bind_params.textures2d_sampled_num)); + } + if (m_bind_params.textures2d_storage_num > 0) + { + m_source += + String(textures_loaded_types).ReplaceStr(U"", String::FromPrintf("%d", m_bind_params.textures2d_storage_num)); } if (m_bind->samplers.samplers_num > 0) { @@ -5402,10 +5586,15 @@ void Spirv::WriteGlobalVariables() vars.Add(String::FromPrintf("%%buf = OpVariable %%_ptr_StorageBuffer__arr_BufferObject_uint_%d StorageBuffer", m_bind->storage_buffers.buffers_num)); } - if (m_bind->textures2D.textures_num > 0) + if (m_bind_params.textures2d_sampled_num > 0) { - vars.Add(String::FromPrintf("%%textures2D = OpVariable %%_ptr_UniformConstant__arr_Image_uint_%d UniformConstant", - m_bind->textures2D.textures_num)); + vars.Add(String::FromPrintf("%%textures2D_S = OpVariable %%_ptr_UniformConstant__arr_ImageS_uint_%d UniformConstant", + m_bind_params.textures2d_sampled_num)); + } + if (m_bind_params.textures2d_storage_num > 0) + { + vars.Add(String::FromPrintf("%%textures2D_L = OpVariable %%_ptr_UniformConstant__arr_ImageL_uint_%d UniformConstant", + m_bind_params.textures2d_storage_num)); } if (m_bind->samplers.samplers_num > 0) { @@ -5817,6 +6006,11 @@ void Spirv::WriteFunctions() m_source += FUNC_ADDC; } + if (m_code.HasAnyOf({ShaderInstructionType::ImageStoreMip})) + { + m_source += FUNC_MIPMAP; + } + if (m_code.HasAnyOf({ShaderInstructionType::VCmpOF32, ShaderInstructionType::VCmpUF32})) { m_source += FUNC_ORDERED; diff --git a/source/emulator/src/Graphics/Tile.cpp b/source/emulator/src/Graphics/Tile.cpp index cfba05e..d8df660 100644 --- a/source/emulator/src/Graphics/Tile.cpp +++ b/source/emulator/src/Graphics/Tile.cpp @@ -210,7 +210,7 @@ public: m_width = width; m_height = height; - if (nfmt == 9 && dfmt == 10) + if ((nfmt == 9 && dfmt == 10) || (nfmt == 0 && dfmt == 10)) { // VK_FORMAT_R8G8B8A8_SRGB; m_bits_per_element = 32; @@ -636,27 +636,37 @@ void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t h static const TextureInfo infos[] = { // clang-format off + // kDataFormatB8G8R8A8UnormSrgb, 512, 512, kTileModeDisplay_LinearAligned { 10, 9, 512, 512, 10, 8, false, {1048576, 262144, 65536, 16384, 4096, 1024, 512, 256, 256, 256, }, { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, } }, { 10, 9, 512, 512, 10, 8, true, {1048576, 262144, 65536, 16384, 4096, 1024, 512, 256, 256, 256, }, { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, } }, + // kDataFormatB8G8R8A8UnormSrgb, 512, 512, kTileModeThin_1dThin { 10, 9, 512, 512, 10, 13, false, {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}, } }, { 10, 9, 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}, } }, + // kDataFormatBc3UnormSrgb, 512, 512, kTileModeDisplay_LinearAligned { 37, 9, 512, 512, 10, 8, false, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, } }, { 37, 9, 512, 512, 10, 8, true, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, } }, + // kDataFormatBc3UnormSrgb, 512, 512, kTileModeThin_1dThin { 37, 9, 512, 512, 10, 13, false, {262144, 65536, 16384, 4096, 1024, 1024, 1024, 1024, 1024, 1024, }, { {128, 128}, {64, 64}, {32, 32}, {16, 16}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, } }, { 37, 9, 512, 512, 10, 13, true, {262144, 65536, 16384, 4096, 1024, 1024, 1024, 1024, 1024, 1024, }, { {128, 128}, {64, 64}, {32, 32}, {16, 16}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, } }, - + // kDataFormatB8G8R8A8Unorm, 512, 512, kTileModeThin_1dThin + { 10, 0, 512, 512, 10, 13, false, {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}, } }, + { 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, 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}, } }, { 10, 0, 256, 256, 9, 14, true, {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}, } }, + // clang-format on }; diff --git a/source/emulator/src/Graphics/Utils.cpp b/source/emulator/src/Graphics/Utils.cpp index ff25f7e..63401b9 100644 --- a/source/emulator/src/Graphics/Utils.cpp +++ b/source/emulator/src/Graphics/Utils.cpp @@ -14,8 +14,8 @@ namespace Kyty::Libs::Graphics { -static void set_image_layout(VkCommandBuffer buffer, VulkanImage* dst_image, uint32_t levels, VkImageAspectFlags aspect_mask, - VkImageLayout old_image_layout, VkImageLayout new_image_layout) +static void set_image_layout(VkCommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level, uint32_t levels, + VkImageAspectFlags aspect_mask, VkImageLayout old_image_layout, VkImageLayout new_image_layout) { EXIT_IF(buffer == nullptr); @@ -32,7 +32,7 @@ static void set_image_layout(VkCommandBuffer buffer, VulkanImage* dst_image, uin image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = dst_image->image; image_memory_barrier.subresourceRange.aspectMask = aspect_mask; - image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.baseMipLevel = base_level; image_memory_barrier.subresourceRange.levelCount = levels; image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.layerCount = 1; @@ -95,7 +95,8 @@ void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, uint32_t auto* vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; - set_image_layout(vk_buffer, dst_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + set_image_layout(vk_buffer, dst_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkBufferImageCopy region {}; region.bufferOffset = 0; @@ -112,12 +113,12 @@ void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, uint32_t vkCmdCopyBufferToImage(vk_buffer, src_buffer->buffer, dst_image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - set_image_layout(vk_buffer, dst_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + set_image_layout(vk_buffer, dst_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } -void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, TextureVulkanImage* dst_image, - const Vector& regions, uint64_t dst_layout) +void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, VulkanImage* dst_image, const Vector& regions, + uint64_t dst_layout) { EXIT_IF(src_buffer == nullptr); EXIT_IF(src_buffer->buffer == nullptr); @@ -137,21 +138,65 @@ void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, TextureV region[index].bufferRowLength = (r.width != r.pitch ? r.pitch : 0); region[index].bufferImageHeight = 0; region[index].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region[index].imageSubresource.mipLevel = index; + region[index].imageSubresource.mipLevel = r.dst_level; region[index].imageSubresource.baseArrayLayer = 0; region[index].imageSubresource.layerCount = 1; - region[index].imageOffset = {0, 0, 0}; + region[index].imageOffset = {r.dst_x, r.dst_y, 0}; region[index].imageExtent = {r.width, r.height, 1}; index++; } - set_image_layout(vk_buffer, dst_image, index, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + set_image_layout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); vkCmdCopyBufferToImage(vk_buffer, src_buffer->buffer, dst_image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, index, region); - set_image_layout(vk_buffer, dst_image, index, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - /*VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/ static_cast(dst_layout)); + set_image_layout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + static_cast(dst_layout)); +} + +void UtilImageToImage(CommandBuffer* buffer, const Vector& regions, VulkanImage* dst_image, uint64_t dst_layout) +{ + EXIT_IF(dst_image == nullptr); + EXIT_IF(dst_image->image == nullptr); + + auto* vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; + + EXIT_NOT_IMPLEMENTED(regions.Size() >= 16); + + set_image_layout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + for (const auto& r: regions) + { + VkImageCopy region; + + auto src_layout = r.src_image->layout; + + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.srcSubresource.mipLevel = r.src_level; + region.srcSubresource.baseArrayLayer = 0; + region.srcSubresource.layerCount = 1; + region.srcOffset = {r.src_x, r.src_y, 0}; + region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.dstSubresource.mipLevel = r.dst_level; + region.dstSubresource.baseArrayLayer = 0; + region.dstSubresource.layerCount = 1; + region.dstOffset = {r.dst_x, r.dst_y, 0}; + region.extent = {r.width, r.height, 1}; + + set_image_layout(vk_buffer, r.src_image, r.src_level, 1, VK_IMAGE_ASPECT_COLOR_BIT, src_layout, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + vkCmdCopyImage(vk_buffer, r.src_image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + set_image_layout(vk_buffer, r.src_image, r.src_level, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + src_layout); + } + + set_image_layout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + static_cast(dst_layout)); } void UtilBlitImage(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchain* dst_swapchain) @@ -167,9 +212,9 @@ void UtilBlitImage(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchai swapchain_image.image = dst_swapchain->swapchain_images[dst_swapchain->current_index]; swapchain_image.layout = VK_IMAGE_LAYOUT_UNDEFINED; - set_image_layout(vk_buffer, src_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + set_image_layout(vk_buffer, src_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - set_image_layout(vk_buffer, &swapchain_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + set_image_layout(vk_buffer, &swapchain_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkImageBlit region {}; @@ -197,7 +242,7 @@ void UtilBlitImage(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchai vkCmdBlitImage(vk_buffer, src_image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapchain_image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, VK_FILTER_LINEAR); - set_image_layout(vk_buffer, src_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + set_image_layout(vk_buffer, src_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } @@ -286,7 +331,7 @@ void UtilSetDepthLayoutOptimal(DepthStencilVulkanImage* image) aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; } - set_image_layout(vk_buffer, image, 1, aspect_mask, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + set_image_layout(vk_buffer, image, 0, 1, aspect_mask, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); buffer.End(); buffer.Execute(); @@ -306,15 +351,15 @@ void UtilSetImageLayoutOptimal(VulkanImage* image) VkImageAspectFlags aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; - set_image_layout(vk_buffer, image, 1, aspect_mask, image->layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + set_image_layout(vk_buffer, image, 0, 1, aspect_mask, image->layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); buffer.End(); buffer.Execute(); buffer.WaitForFence(); } -void UtilFillImage(GraphicContext* ctx, TextureVulkanImage* image, const void* src_data, uint64_t size, - const Vector& regions, uint64_t dst_layout) +void UtilFillImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size, const Vector& regions, + uint64_t dst_layout) { EXIT_IF(ctx == nullptr); EXIT_IF(image == nullptr); @@ -343,6 +388,23 @@ void UtilFillImage(GraphicContext* ctx, TextureVulkanImage* image, const void* s VulkanDeleteBuffer(ctx, &staging_buffer); } +void UtilFillImage(GraphicContext* ctx, const Vector& regions, VulkanImage* dst_image, uint64_t dst_layout) +{ + EXIT_IF(ctx == nullptr); + EXIT_IF(dst_image == nullptr); + + CommandBuffer buffer; + buffer.SetQueue(GraphicContext::QUEUE_UTIL); + + EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); + + buffer.Begin(); + UtilImageToImage(&buffer, regions, dst_image, dst_layout); + buffer.End(); + buffer.Execute(); + buffer.WaitForFence(); +} + void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size) { EXIT_IF(src_buffer == nullptr); diff --git a/source/emulator/src/Graphics/Window.cpp b/source/emulator/src/Graphics/Window.cpp index 7f1e4dc..36a3822 100644 --- a/source/emulator/src/Graphics/Window.cpp +++ b/source/emulator/src/Graphics/Window.cpp @@ -1329,6 +1329,12 @@ static VkPhysicalDevice VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceK } } + if (device_features.fragmentStoresAndAtomics != VK_TRUE) + { + printf("fragmentStoresAndAtomics is not supported\n"); + skip_device = true; + } + if (!skip_device) { uint32_t extensions_count = 0; @@ -1518,7 +1524,8 @@ static VkDevice VulkanCreateDevice(VkPhysicalDevice physical_device, VkSurfaceKH queue_create_info.queueCount = queue_count; queue_create_info.pQueuePriorities = queue_priority.GetDataConst(); - // VkPhysicalDeviceFeatures device_features {}; + VkPhysicalDeviceFeatures device_features {}; + device_features.fragmentStoresAndAtomics = VK_TRUE; VkDeviceCreateInfo create_info {}; create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; @@ -1530,7 +1537,7 @@ static VkDevice VulkanCreateDevice(VkPhysicalDevice physical_device, VkSurfaceKH create_info.ppEnabledLayerNames = (r->enable_validation_layers ? r->required_layers.GetDataConst() : nullptr); create_info.enabledExtensionCount = device_extensions.Size(); create_info.ppEnabledExtensionNames = device_extensions.GetDataConst(); - create_info.pEnabledFeatures = nullptr; //&device_features; + create_info.pEnabledFeatures = &device_features; VkDevice device = nullptr;