From 38bde7e8b3536c7602ba55858052de19c5caacda Mon Sep 17 00:00:00 2001 From: InoriRus Date: Mon, 14 Feb 2022 11:58:44 +1000 Subject: [PATCH] render to texture --- appveyor.yml | 2 +- source/CMakeLists.txt | 2 +- source/emulator/CMakeLists.txt | 1 + .../Emulator/Graphics/GraphicContext.h | 25 +- .../Emulator/Graphics/GraphicsRender.h | 4 + .../{ => Objects}/DepthStencilBuffer.h | 8 +- .../Graphics/{ => Objects}/GpuMemory.h | 36 +- .../Graphics/{ => Objects}/IndexBuffer.h | 8 +- .../Emulator/Graphics/{ => Objects}/Label.h | 8 +- .../Emulator/Graphics/Objects/RenderTexture.h | 55 + .../Graphics/{ => Objects}/StorageBuffer.h | 8 +- .../Emulator/Graphics/{ => Objects}/Texture.h | 12 +- .../Graphics/{ => Objects}/VertexBuffer.h | 8 +- .../Graphics/{ => Objects}/VideoOutBuffer.h | 8 +- .../emulator/include/Emulator/Graphics/Tile.h | 6 +- .../include/Emulator/Graphics/Utils.h | 12 +- source/emulator/src/Graphics/GpuMemory.cpp | 960 ------------ source/emulator/src/Graphics/Graphics.cpp | 4 +- .../emulator/src/Graphics/GraphicsRender.cpp | 431 ++++-- source/emulator/src/Graphics/GraphicsRun.cpp | 47 +- .../{ => Objects}/DepthStencilBuffer.cpp | 7 +- .../src/Graphics/Objects/GpuMemory.cpp | 1353 +++++++++++++++++ .../Graphics/{ => Objects}/IndexBuffer.cpp | 2 +- .../src/Graphics/{ => Objects}/Label.cpp | 2 +- .../src/Graphics/Objects/RenderTexture.cpp | 211 +++ .../Graphics/{ => Objects}/StorageBuffer.cpp | 2 +- .../src/Graphics/{ => Objects}/Texture.cpp | 11 +- .../Graphics/{ => Objects}/VertexBuffer.cpp | 2 +- .../Graphics/{ => Objects}/VideoOutBuffer.cpp | 9 +- source/emulator/src/Graphics/Shader.cpp | 2 +- source/emulator/src/Graphics/Tile.cpp | 32 +- source/emulator/src/Graphics/Utils.cpp | 48 +- source/emulator/src/Graphics/VideoOut.cpp | 6 +- source/emulator/src/Kernel/Memory.cpp | 2 +- source/emulator/src/Kernel/Semaphore.cpp | 22 +- 35 files changed, 2119 insertions(+), 1237 deletions(-) rename source/emulator/include/Emulator/Graphics/{ => Objects}/DepthStencilBuffer.h (82%) rename source/emulator/include/Emulator/Graphics/{ => Objects}/GpuMemory.h (74%) rename source/emulator/include/Emulator/Graphics/{ => Objects}/IndexBuffer.h (76%) rename source/emulator/include/Emulator/Graphics/{ => Objects}/Label.h (87%) create mode 100644 source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h rename source/emulator/include/Emulator/Graphics/{ => Objects}/StorageBuffer.h (77%) rename source/emulator/include/Emulator/Graphics/{ => Objects}/Texture.h (83%) rename source/emulator/include/Emulator/Graphics/{ => Objects}/VertexBuffer.h (75%) rename source/emulator/include/Emulator/Graphics/{ => Objects}/VideoOutBuffer.h (84%) delete mode 100644 source/emulator/src/Graphics/GpuMemory.cpp rename source/emulator/src/Graphics/{ => Objects}/DepthStencilBuffer.cpp (96%) create mode 100644 source/emulator/src/Graphics/Objects/GpuMemory.cpp rename source/emulator/src/Graphics/{ => Objects}/IndexBuffer.cpp (98%) rename source/emulator/src/Graphics/{ => Objects}/Label.cpp (99%) create mode 100644 source/emulator/src/Graphics/Objects/RenderTexture.cpp rename source/emulator/src/Graphics/{ => Objects}/StorageBuffer.cpp (98%) rename source/emulator/src/Graphics/{ => Objects}/Texture.cpp (97%) rename source/emulator/src/Graphics/{ => Objects}/VertexBuffer.cpp (98%) rename source/emulator/src/Graphics/{ => Objects}/VideoOutBuffer.cpp (95%) diff --git a/appveyor.yml b/appveyor.yml index 1883953..9a5f913 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.0.8.build-{build} +version: 0.0.9.build-{build} image: Visual Studio 2019 environment: matrix: diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 1b46d63..bf42e1f 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.8) +project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.9) include(src_script.cmake) diff --git a/source/emulator/CMakeLists.txt b/source/emulator/CMakeLists.txt index 8a263ed..d884480 100644 --- a/source/emulator/CMakeLists.txt +++ b/source/emulator/CMakeLists.txt @@ -3,6 +3,7 @@ file(GLOB emulator_src src/*.cpp src/Libs/*.cpp src/Graphics/*.cpp + src/Graphics/Objects/*.cpp src/Kernel/*.cpp include/*.h ) diff --git a/source/emulator/include/Emulator/Graphics/GraphicContext.h b/source/emulator/include/Emulator/Graphics/GraphicContext.h index a191af4..ce042e9 100644 --- a/source/emulator/include/Emulator/Graphics/GraphicContext.h +++ b/source/emulator/include/Emulator/Graphics/GraphicContext.h @@ -65,31 +65,30 @@ struct VulkanMemory uint64_t unique_id = 0; }; -struct VideoOutVulkanImage +struct VulkanImage { VkFormat format = VK_FORMAT_UNDEFINED; VkExtent2D extent = {}; VkImage image = nullptr; VkImageView image_view = nullptr; + VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; Graphics::VulkanMemory memory; }; -struct DepthStencilVulkanImage +struct VideoOutVulkanImage: public VulkanImage { - VkFormat format = VK_FORMAT_UNDEFINED; - VkExtent2D extent = {}; - VkImage image = nullptr; - VkImageView image_view = nullptr; - Graphics::VulkanMemory memory; }; -struct TextureVulkanImage +struct DepthStencilVulkanImage: public VulkanImage +{ +}; + +struct TextureVulkanImage: public VulkanImage +{ +}; + +struct RenderTextureVulkanImage: public VulkanImage { - VkFormat format = VK_FORMAT_UNDEFINED; - VkExtent2D extent = {}; - VkImage image = nullptr; - VkImageView image_view = nullptr; - Graphics::VulkanMemory memory; }; struct VulkanBuffer diff --git a/source/emulator/include/Emulator/Graphics/GraphicsRender.h b/source/emulator/include/Emulator/Graphics/GraphicsRender.h index cdc4084..7bc18a3 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 RenderTextureVulkanImage; struct VulkanCommandPool; struct VulkanBuffer; struct VulkanFramebuffer; @@ -82,11 +83,14 @@ void GraphicsRenderWriteBack(); void GraphicsRenderDispatchDirect(CommandBuffer* buffer, HardwareContext* ctx, uint32_t thread_group_x, uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode); void GraphicsRenderMemoryBarrier(CommandBuffer* buffer); +void GraphicsRenderRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size); void DeleteFramebuffer(VideoOutVulkanImage* image); void DeleteFramebuffer(DepthStencilVulkanImage* image); +void DeleteFramebuffer(RenderTextureVulkanImage* image); void DeleteDescriptor(VulkanBuffer* buffer); void DeleteDescriptor(TextureVulkanImage* image); +void DeleteDescriptor(RenderTextureVulkanImage* image); int GraphicsRenderAddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata); int GraphicsRenderDeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id); diff --git a/source/emulator/include/Emulator/Graphics/DepthStencilBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/DepthStencilBuffer.h similarity index 82% rename from source/emulator/include/Emulator/Graphics/DepthStencilBuffer.h rename to source/emulator/include/Emulator/Graphics/Objects/DepthStencilBuffer.h index 32d71f7..152b3e8 100644 --- a/source/emulator/include/Emulator/Graphics/DepthStencilBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/DepthStencilBuffer.h @@ -1,10 +1,10 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_DEPTHSTENCILBUFFER_H_ -#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_DEPTHSTENCILBUFFER_H_ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_DEPTHSTENCILBUFFER_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_DEPTHSTENCILBUFFER_H_ #include "Kyty/Core/Common.h" #include "Emulator/Common.h" -#include "Emulator/Graphics/GpuMemory.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #ifdef KYTY_EMU_ENABLED @@ -45,4 +45,4 @@ public: #endif // KYTY_EMU_ENABLED -#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_DEPTHSTENCILBUFFER_H_ */ +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_DEPTHSTENCILBUFFER_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/GpuMemory.h b/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h similarity index 74% rename from source/emulator/include/Emulator/Graphics/GpuMemory.h rename to source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h index 8dacae0..e200f2a 100644 --- a/source/emulator/include/Emulator/Graphics/GpuMemory.h +++ b/source/emulator/include/Emulator/Graphics/Objects/GpuMemory.h @@ -1,7 +1,8 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GPUMEMORY_H_ -#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GPUMEMORY_H_ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_GPUMEMORY_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_GPUMEMORY_H_ #include "Kyty/Core/Common.h" +#include "Kyty/Core/Vector.h" #include "Emulator/Common.h" @@ -12,9 +13,7 @@ namespace Kyty::Libs::Graphics { struct GraphicContext; struct VulkanMemory; struct VulkanBuffer; -struct TextureVulkanImage; -struct VideoOutVulkanImage; -struct DepthStencilVulkanImage; +struct VulkanImage; enum class GpuMemoryMode { @@ -24,7 +23,7 @@ enum class GpuMemoryMode ReadWrite }; -enum class GpuMemoryObjectType +enum class GpuMemoryObjectType : uint64_t { Invalid, VideoOutBuffer, @@ -33,7 +32,16 @@ enum class GpuMemoryObjectType IndexBuffer, VertexBuffer, StorageBuffer, - Texture + Texture, + RenderTexture, + + Max +}; + +struct GpuMemoryObject +{ + GpuMemoryObjectType type = GpuMemoryObjectType::Invalid; + void* obj = nullptr; }; class GpuObject @@ -68,21 +76,21 @@ void GpuMemoryInit(); void GpuMemorySetAllocatedRange(uint64_t vaddr, uint64_t size); void GpuMemoryFree(GraphicContext* ctx, uint64_t vaddr, uint64_t size); -void* GpuMemoryGetObject(GraphicContext* ctx, uint64_t vaddr, uint64_t size, const GpuObject& info); -void* GpuMemoryGetObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info); -void GpuMemoryResetHash(GraphicContext* ctx, uint64_t vaddr, uint64_t size, GpuMemoryObjectType type); +void* GpuMemoryCreateObject(GraphicContext* ctx, uint64_t vaddr, uint64_t size, const GpuObject& info); +void* GpuMemoryCreateObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info); +void GpuMemoryResetHash(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, GpuMemoryObjectType type); void GpuMemoryDbgDump(); void GpuMemoryFlush(GraphicContext* ctx); void GpuMemoryFrameDone(); void GpuMemoryWriteBack(GraphicContext* ctx); +Vector GpuMemoryFindObjects(uint64_t vaddr, uint64_t size); + bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* mem); void VulkanFree(GraphicContext* ctx, VulkanMemory* mem); void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* mem, void** data); void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* mem); -void VulkanBindImageMemory(GraphicContext* ctx, TextureVulkanImage* image, VulkanMemory* mem); -void VulkanBindImageMemory(GraphicContext* ctx, VideoOutVulkanImage* image, VulkanMemory* mem); -void VulkanBindImageMemory(GraphicContext* ctx, DepthStencilVulkanImage* image, VulkanMemory* mem); +void VulkanBindImageMemory(GraphicContext* ctx, VulkanImage* image, VulkanMemory* mem); void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* mem); void GpuMemoryRegisterOwner(uint32_t* owner_handle, const char* name); @@ -96,4 +104,4 @@ void GpuMemoryUnregisterResource(uint32_t resource_handle); #endif // KYTY_EMU_ENABLED -#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GPUMEMORY_H_ */ +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_GPUMEMORY_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/IndexBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/IndexBuffer.h similarity index 76% rename from source/emulator/include/Emulator/Graphics/IndexBuffer.h rename to source/emulator/include/Emulator/Graphics/Objects/IndexBuffer.h index 378e871..df7dfd7 100644 --- a/source/emulator/include/Emulator/Graphics/IndexBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/IndexBuffer.h @@ -1,10 +1,10 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_INDEXBUFFER_H_ -#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_INDEXBUFFER_H_ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_INDEXBUFFER_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_INDEXBUFFER_H_ #include "Kyty/Core/Common.h" #include "Emulator/Common.h" -#include "Emulator/Graphics/GpuMemory.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #ifdef KYTY_EMU_ENABLED @@ -34,4 +34,4 @@ public: #endif // KYTY_EMU_ENABLED -#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_INDEXBUFFER_H_ */ +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_INDEXBUFFER_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/Label.h b/source/emulator/include/Emulator/Graphics/Objects/Label.h similarity index 87% rename from source/emulator/include/Emulator/Graphics/Label.h rename to source/emulator/include/Emulator/Graphics/Objects/Label.h index 23aeef6..848ec9e 100644 --- a/source/emulator/include/Emulator/Graphics/Label.h +++ b/source/emulator/include/Emulator/Graphics/Objects/Label.h @@ -1,10 +1,10 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_LABEL_H_ -#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_LABEL_H_ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_LABEL_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_LABEL_H_ #include "Kyty/Core/Common.h" #include "Emulator/Common.h" -#include "Emulator/Graphics/GpuMemory.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #ifdef KYTY_EMU_ENABLED @@ -60,4 +60,4 @@ void LabelSet(CommandBuffer* buffer, Label* label); #endif // KYTY_EMU_ENABLED -#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_LABEL_H_ */ +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_LABEL_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h b/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h new file mode 100644 index 0000000..4a283d4 --- /dev/null +++ b/source/emulator/include/Emulator/Graphics/Objects/RenderTexture.h @@ -0,0 +1,55 @@ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_RENDERTEXTURE_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_RENDERTEXTURE_H_ + +#include "Kyty/Core/Common.h" + +#include "Emulator/Common.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" + +#ifdef KYTY_EMU_ENABLED + +namespace Kyty::Libs::Graphics { + +struct GraphicContext; +struct VulkanMemory; + +enum class RenderTextureFormat : uint64_t +{ + R8G8B8A8Unorm +}; + +class RenderTextureObject: public GpuObject +{ +public: + static constexpr int PARAM_FORMAT = 0; + static constexpr int PARAM_WIDTH = 1; + static constexpr int PARAM_HEIGHT = 2; + static constexpr int PARAM_TILED = 3; + static constexpr int PARAM_NEO = 4; + static constexpr int PARAM_PITCH = 5; + + explicit RenderTextureObject(RenderTextureFormat pixel_format, uint32_t width, uint32_t height, bool tiled, bool neo, uint32_t pitch) + { + params[PARAM_FORMAT] = static_cast(pixel_format); + params[PARAM_WIDTH] = width; + params[PARAM_HEIGHT] = height; + params[PARAM_TILED] = tiled ? 1 : 0; + params[PARAM_NEO] = neo ? 1 : 0; + params[PARAM_PITCH] = pitch; + check_hash = true; + 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; + + [[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_RENDERTEXTURE_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/StorageBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h similarity index 77% rename from source/emulator/include/Emulator/Graphics/StorageBuffer.h rename to source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h index f319abb..9656023 100644 --- a/source/emulator/include/Emulator/Graphics/StorageBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/StorageBuffer.h @@ -1,10 +1,10 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_STORAGEBUFFER_H_ -#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_STORAGEBUFFER_H_ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_STORAGEBUFFER_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_STORAGEBUFFER_H_ #include "Kyty/Core/Common.h" #include "Emulator/Common.h" -#include "Emulator/Graphics/GpuMemory.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #ifdef KYTY_EMU_ENABLED @@ -37,4 +37,4 @@ public: #endif // KYTY_EMU_ENABLED -#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_STORAGEBUFFER_H_ */ +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_STORAGEBUFFER_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/Texture.h b/source/emulator/include/Emulator/Graphics/Objects/Texture.h similarity index 83% rename from source/emulator/include/Emulator/Graphics/Texture.h rename to source/emulator/include/Emulator/Graphics/Objects/Texture.h index e3b469c..31b2c55 100644 --- a/source/emulator/include/Emulator/Graphics/Texture.h +++ b/source/emulator/include/Emulator/Graphics/Objects/Texture.h @@ -1,10 +1,10 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TEXTURE_H_ -#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TEXTURE_H_ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_TEXTURE_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_TEXTURE_H_ #include "Kyty/Core/Common.h" #include "Emulator/Common.h" -#include "Emulator/Graphics/GpuMemory.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #ifdef KYTY_EMU_ENABLED @@ -28,7 +28,7 @@ public: static constexpr int PARAM_NEO = 6; static constexpr int PARAM_SWIZZLE = 7; - TextureObject(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, bool htile, bool neo, + 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) { params[PARAM_DFMT_NFMT] = (static_cast(dfmt) << 32u) | nfmt; @@ -36,7 +36,7 @@ public: params[PARAM_WIDTH_HEIGHT] = (static_cast(width) << 32u) | height; params[PARAM_USAGE] = usage; params[PARAM_LEVELS] = levels; - params[PARAM_TILE] = htile ? 1 : 0; + params[PARAM_TILE] = tile; params[PARAM_NEO] = neo ? 1 : 0; params[PARAM_SWIZZLE] = swizzle; check_hash = true; @@ -55,4 +55,4 @@ public: #endif // KYTY_EMU_ENABLED -#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TEXTURE_H_ */ +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_TEXTURE_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/VertexBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/VertexBuffer.h similarity index 75% rename from source/emulator/include/Emulator/Graphics/VertexBuffer.h rename to source/emulator/include/Emulator/Graphics/Objects/VertexBuffer.h index 666c799..81f0da5 100644 --- a/source/emulator/include/Emulator/Graphics/VertexBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/VertexBuffer.h @@ -1,10 +1,10 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VERTEXBUFFER_H_ -#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VERTEXBUFFER_H_ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_VERTEXBUFFER_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_VERTEXBUFFER_H_ #include "Kyty/Core/Common.h" #include "Emulator/Common.h" -#include "Emulator/Graphics/GpuMemory.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #ifdef KYTY_EMU_ENABLED @@ -34,4 +34,4 @@ public: #endif // KYTY_EMU_ENABLED -#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VERTEXBUFFER_H_ */ +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_VERTEXBUFFER_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/VideoOutBuffer.h b/source/emulator/include/Emulator/Graphics/Objects/VideoOutBuffer.h similarity index 84% rename from source/emulator/include/Emulator/Graphics/VideoOutBuffer.h rename to source/emulator/include/Emulator/Graphics/Objects/VideoOutBuffer.h index f90f3c0..e678037 100644 --- a/source/emulator/include/Emulator/Graphics/VideoOutBuffer.h +++ b/source/emulator/include/Emulator/Graphics/Objects/VideoOutBuffer.h @@ -1,10 +1,10 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUTBUFFER_H_ -#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUTBUFFER_H_ +#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_VIDEOOUTBUFFER_H_ +#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_VIDEOOUTBUFFER_H_ #include "Kyty/Core/Common.h" #include "Emulator/Common.h" -#include "Emulator/Graphics/GpuMemory.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #ifdef KYTY_EMU_ENABLED @@ -47,4 +47,4 @@ public: #endif // KYTY_EMU_ENABLED -#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUTBUFFER_H_ */ +#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_OBJECTS_VIDEOOUTBUFFER_H_ */ diff --git a/source/emulator/include/Emulator/Graphics/Tile.h b/source/emulator/include/Emulator/Graphics/Tile.h index 4ee9282..1998391 100644 --- a/source/emulator/include/Emulator/Graphics/Tile.h +++ b/source/emulator/include/Emulator/Graphics/Tile.h @@ -15,6 +15,8 @@ enum class TileMode VideoOutTiled, TextureLinear, TextureTiled, + // RenderTextureLinear, + // RenderTextureTiled, }; void TileInit(); @@ -25,8 +27,8 @@ void TileConvertTiledToLinear(void* dst, const void* src, TileMode mode, uint32_ void TileGetDepthSize(uint32_t width, uint32_t height, uint32_t z_format, uint32_t stencil_format, bool htile, bool neo, uint32_t* stencil_size, uint32_t* htile_size, uint32_t* depth_size, uint32_t* pitch); void TileGetVideoOutSize(uint32_t width, uint32_t height, bool tile, bool neo, uint32_t* size, uint32_t* pitch); -void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, bool tile, bool neo, - uint32_t* total_size, uint32_t* level_sizes, uint32_t* padded_width, uint32_t* padded_height); +void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile, + bool neo, uint32_t* total_size, uint32_t* level_sizes, uint32_t* padded_width, uint32_t* padded_height); } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/include/Emulator/Graphics/Utils.h b/source/emulator/include/Emulator/Graphics/Utils.h index eea164e..c9be651 100644 --- a/source/emulator/include/Emulator/Graphics/Utils.h +++ b/source/emulator/include/Emulator/Graphics/Utils.h @@ -17,7 +17,7 @@ namespace Kyty::Libs::Graphics { class CommandBuffer; struct GraphicContext; struct VulkanBuffer; -struct VideoOutVulkanImage; +struct VulkanImage; struct TextureVulkanImage; struct DepthStencilVulkanImage; struct VulkanSwapchain; @@ -30,16 +30,16 @@ struct BufferImageCopy uint32_t pitch; }; -void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, uint32_t src_pitch, VideoOutVulkanImage* dst_image); +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 UtilBlitImage(CommandBuffer* buffer, VideoOutVulkanImage* src_image, VulkanSwapchain* dst_swapchain); -void UtilFillImage(GraphicContext* ctx, VideoOutVulkanImage* dst_image, const void* src_data, uint64_t size, uint32_t src_pitch); +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 UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size); -void UtilSetImageLayoutOptimal(DepthStencilVulkanImage* image); -void UtilSetImageLayoutOptimal(VideoOutVulkanImage* image); +void UtilSetDepthLayoutOptimal(DepthStencilVulkanImage* image); +void UtilSetImageLayoutOptimal(VulkanImage* image); void VulkanCreateBuffer(GraphicContext* gctx, uint64_t size, VulkanBuffer* buffer); void VulkanDeleteBuffer(GraphicContext* gctx, VulkanBuffer* buffer); diff --git a/source/emulator/src/Graphics/GpuMemory.cpp b/source/emulator/src/Graphics/GpuMemory.cpp deleted file mode 100644 index 5a08244..0000000 --- a/source/emulator/src/Graphics/GpuMemory.cpp +++ /dev/null @@ -1,960 +0,0 @@ -#include "Emulator/Graphics/GpuMemory.h" - -#include "Kyty/Core/DbgAssert.h" -#include "Kyty/Core/MagicEnum.h" -#include "Kyty/Core/String.h" -#include "Kyty/Core/Threads.h" -#include "Kyty/Core/Vector.h" - -#include "Emulator/Graphics/GraphicContext.h" -#include "Emulator/Profiler.h" - -#include -#include -#include - -//#define XXH_INLINE_ALL -#include - -#ifdef KYTY_EMU_ENABLED - -namespace Kyty::Libs::Graphics { - -class GpuMemory -{ -public: - GpuMemory() { EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); } - virtual ~GpuMemory() { KYTY_NOT_IMPLEMENTED; } - KYTY_CLASS_NO_COPY(GpuMemory); - - bool IsAllocated(uint64_t vaddr, uint64_t size); - void SetAllocatedRange(uint64_t vaddr, uint64_t size); - void Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size); - - void* GetObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info); - void ResetHash(GraphicContext* ctx, uint64_t* vaddr, uint64_t* size, int vaddr_num, GpuMemoryObjectType type); - void FrameDone(); - - // Sync: GPU -> CPU - void WriteBack(GraphicContext* ctx); - - // Sync: CPU -> GPU - void Flush(GraphicContext* ctx); - - void DbgDump(); - -private: - static constexpr int OBJ_OVERLAPS_MAX = 2; - static constexpr int VADDR_BLOCKS_MAX = 3; - - struct AllocatedRange - { - uint64_t vaddr; - uint64_t size; - }; - - struct ObjectInfo - { - void* obj = nullptr; - 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; - GpuObject::update_func_t update_func = nullptr; - uint64_t use_last_frame = 0; - uint64_t use_num = 0; - bool in_use = false; - bool read_only = false; - bool check_hash = false; - VulkanMemory mem; - }; - - struct Object - { - uint64_t vaddr[VADDR_BLOCKS_MAX] = {}; - uint64_t size[VADDR_BLOCKS_MAX] = {}; - int vaddr_num = 0; - ObjectInfo overlaps[OBJ_OVERLAPS_MAX]; - int overlaps_num = 0; - bool free = true; - }; - - void Free(GraphicContext* ctx, Object& h); - - Core::Mutex m_mutex; - - Vector m_allocated; - Vector m_objects; - uint64_t m_objects_size = 0; - uint64_t m_current_frame = 0; -}; - -class GpuResources -{ -public: - struct Info - { - uint32_t owner = 0; - bool free = true; - uint64_t memory = 0; - size_t size = 0; - String name; - uint32_t type = 0; - uint64_t user_data = 0; - }; - - GpuResources() { EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); } - virtual ~GpuResources() { KYTY_NOT_IMPLEMENTED; } - KYTY_CLASS_NO_COPY(GpuResources); - - uint32_t AddOwner(const String& name); - uint32_t AddResource(uint32_t owner_handle, uint64_t memory, size_t size, const String& name, uint32_t type, uint64_t user_data); - void DeleteOwner(uint32_t owner_handle); - void DeleteResources(uint32_t owner_handle); - void DeleteResource(uint32_t resource_handle); - - bool FindInfo(uint64_t memory, Info* dst); - -private: - struct Owner - { - String name; - bool free = true; - }; - - Core::Mutex m_mutex; - - Vector m_owners; - Vector m_infos; -}; - -static GpuMemory* g_gpu_memory = nullptr; -static GpuResources* g_gpu_resources = nullptr; - -uint32_t GpuResources::AddOwner(const String& name) -{ - Core::LockGuard lock(m_mutex); - - Owner n; - n.name = name; - n.free = false; - - uint32_t index = 0; - for (auto& b: m_owners) - { - if (b.free) - { - b = n; - return index; - } - index++; - } - - m_owners.Add(n); - - return index; -} - -uint32_t GpuResources::AddResource(uint32_t owner_handle, uint64_t memory, size_t size, const String& name, uint32_t type, - uint64_t user_data) -{ - Core::LockGuard lock(m_mutex); - - EXIT_NOT_IMPLEMENTED(!m_owners.IndexValid(owner_handle)); - EXIT_NOT_IMPLEMENTED(memory == 0); - - Info info; - info.owner = owner_handle; - info.memory = memory; - info.free = false; - info.name = name; - info.size = size; - info.type = type; - info.user_data = user_data; - - uint32_t index = 0; - for (auto& i: m_infos) - { - if (i.free) - { - i = info; - return index; - } - index++; - } - - m_infos.Add(info); - - return index; -} - -void GpuResources::DeleteOwner(uint32_t owner_handle) -{ - Core::LockGuard lock(m_mutex); - - EXIT_NOT_IMPLEMENTED(!m_owners.IndexValid(owner_handle)); - - for (auto& i: m_infos) - { - if (!i.free && i.owner == owner_handle) - { - i.free = true; - } - } - - EXIT_NOT_IMPLEMENTED(m_owners[owner_handle].free); - - m_owners[owner_handle].free = true; -} - -void GpuResources::DeleteResources(uint32_t owner_handle) -{ - Core::LockGuard lock(m_mutex); - - EXIT_NOT_IMPLEMENTED(!m_owners.IndexValid(owner_handle)); - - for (auto& i: m_infos) - { - if (!i.free && i.owner == owner_handle) - { - i.free = true; - } - } -} - -void GpuResources::DeleteResource(uint32_t resource_handle) -{ - Core::LockGuard lock(m_mutex); - - EXIT_NOT_IMPLEMENTED(!m_infos.IndexValid(resource_handle)); - - EXIT_NOT_IMPLEMENTED(m_infos[resource_handle].free); - - m_infos[resource_handle].free = true; -} - -bool GpuResources::FindInfo(uint64_t memory, Info* dst) -{ - EXIT_IF(dst == nullptr); - - Core::LockGuard lock(m_mutex); - - // NOLINTNEXTLINE(readability-use-anyofallof) - for (const auto& i: m_infos) - { - if (!i.free && memory >= i.memory && memory < i.memory + i.size) - { - *dst = i; - return true; - } - } - - return false; -} - -void GpuMemory::SetAllocatedRange(uint64_t vaddr, uint64_t size) -{ - EXIT_IF(size == 0); - - EXIT_NOT_IMPLEMENTED(IsAllocated(vaddr, size)); - - Core::LockGuard lock(m_mutex); - - AllocatedRange r {}; - r.vaddr = vaddr; - r.size = size; - - m_allocated.Add(r); -} - -bool GpuMemory::IsAllocated(uint64_t vaddr, uint64_t size) -{ - EXIT_IF(size == 0); - - Core::LockGuard lock(m_mutex); - - return std::any_of(m_allocated.begin(), m_allocated.end(), - [vaddr, size](auto& r) { - return ((vaddr >= r.vaddr && vaddr < r.vaddr + r.size) || - ((vaddr + size - 1) >= r.vaddr && (vaddr + size - 1) < r.vaddr + r.size)); - }); -} - -static uint64_t calc_hash(const uint8_t* buf, uint64_t size) -{ - KYTY_PROFILER_FUNCTION(); - - return (size > 0 && buf != nullptr ? XXH64(buf, size, 0) : 0); -} - -static bool vaddr_equal(const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const uint64_t* vaddr2, const uint64_t* size2, - int vaddr_num2) -{ - if (vaddr_num != vaddr_num2) - { - return false; - } - for (int i = 0; i < vaddr_num; i++) - { - if (vaddr[i] != vaddr2[i] || size[i] != size2[i]) - { - return false; - } - } - return true; -} - -static bool vaddr_overlap(const uint64_t* hvaddr, const uint64_t* hsize, int vaddr_num, uint64_t vaddr, uint64_t size) -{ - for (int i = 0; i < vaddr_num; i++) - { - if ((vaddr >= hvaddr[i] && vaddr < hvaddr[i] + hsize[i]) || - ((vaddr + size - 1) >= hvaddr[i] && (vaddr + size - 1) < hvaddr[i] + hsize[i])) - { - return true; - } - } - return false; -} - -// NOLINTNEXTLINE(readability-function-cognitive-complexity) -void* GpuMemory::GetObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info) -{ - EXIT_IF(info.type == GpuMemoryObjectType::Invalid); - EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num > VADDR_BLOCKS_MAX || vaddr_num <= 0); - - Core::LockGuard lock(m_mutex); - - uint64_t hash[VADDR_BLOCKS_MAX] = {}; - - for (int vi = 0; vi < vaddr_num; vi++) - { - EXIT_IF(size[vi] == 0); - - if (info.check_hash) - { - hash[vi] = calc_hash(reinterpret_cast(vaddr[vi]), size[vi]); - } else - { - hash[vi] = 0; - } - } - - Object* update_object = nullptr; - - for (auto& h: m_objects) - { - if (!h.free && vaddr_equal(h.vaddr, h.size, h.vaddr_num, vaddr, size, vaddr_num)) - { - for (int oi = 0; oi < h.overlaps_num; oi++) - { - auto& o = h.overlaps[oi]; - if (o.type == info.type && info.Equal(o.params)) - { - bool need_update = false; - for (int vi = 0; vi < h.vaddr_num; vi++) - { - if (o.hash[vi] != hash[vi]) - { - printf("Update (CPU -> GPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", - Core::EnumName(o.type).C_Str(), h.vaddr[vi], h.size[vi]); - need_update = true; - o.hash[vi] = hash[vi]; - } - } - if (need_update) - { - EXIT_IF(o.update_func == nullptr); - o.update_func(ctx, o.params, o.obj, vaddr, size, vaddr_num); - } - o.use_num++; - o.use_last_frame = m_current_frame; - o.in_use = true; - o.read_only = info.read_only; - o.check_hash = info.check_hash; - return o.obj; - } - } - - if (h.overlaps_num == 1 && - (h.overlaps[0].type == GpuMemoryObjectType::VideoOutBuffer && info.type == GpuMemoryObjectType::StorageBuffer)) - { - update_object = &h; - break; - } - - // EXIT("not implemented"); - - Free(ctx, h); - break; - } - - for (int vi = 0; vi < vaddr_num; vi++) - { - if (!h.free && vaddr_overlap(h.vaddr, h.size, h.overlaps_num, vaddr[vi], size[vi])) - { - if (h.overlaps_num == 1 && - (h.overlaps[0].type == GpuMemoryObjectType::Label || h.overlaps[0].type == GpuMemoryObjectType::StorageBuffer)) - { - Free(ctx, h); - } else - { - KYTY_NOT_IMPLEMENTED; - } - } - } - } - - for (int vi = 0; vi < vaddr_num; vi++) - { - EXIT_NOT_IMPLEMENTED(!IsAllocated(vaddr[vi], size[vi])); - } - - ObjectInfo o {}; - - for (int i = 0; i < GpuObject::PARAMS_MAX; i++) - { - o.params[i] = info.params[i]; - } - - o.type = info.type; - o.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); - o.write_back_func = info.GetWriteBackFunc(); - o.delete_func = info.GetDeleteFunc(); - o.update_func = info.GetUpdateFunc(); - o.use_num = 1; - o.use_last_frame = m_current_frame; - o.in_use = true; - o.read_only = info.read_only; - o.check_hash = info.check_hash; - - bool updated = false; - - if (update_object != nullptr) - { - EXIT_IF(update_object->overlaps_num >= OBJ_OVERLAPS_MAX); - update_object->overlaps[update_object->overlaps_num++] = o; - - updated = true; - } else - { - for (auto& u: m_objects) - { - if (u.free) - { - u.overlaps_num = 1; - u.overlaps[0] = o; - u.free = false; - for (int vi = 0; vi < vaddr_num; vi++) - { - u.vaddr[vi] = vaddr[vi]; - u.size[vi] = size[vi]; - m_objects_size += size[vi]; - } - u.vaddr_num = vaddr_num; - updated = true; - break; - } - } - } - - if (!updated) - { - Object h {}; - for (int vi = 0; vi < vaddr_num; vi++) - { - h.vaddr[vi] = vaddr[vi]; - h.size[vi] = size[vi]; - m_objects_size += size[vi]; - } - h.vaddr_num = vaddr_num; - h.overlaps_num = 1; - h.overlaps[0] = o; - h.free = false; - m_objects.Add(h); - } - - return o.obj; -} - -void GpuMemory::ResetHash(GraphicContext* /*ctx*/, uint64_t* vaddr, uint64_t* size, int vaddr_num, GpuMemoryObjectType type) -{ - EXIT_IF(type == GpuMemoryObjectType::Invalid); - EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num > VADDR_BLOCKS_MAX || vaddr_num <= 0); - - Core::LockGuard lock(m_mutex); - - uint64_t new_hash = 0; - - for (auto& h: m_objects) - { - if (!h.free && vaddr_equal(h.vaddr, h.size, h.vaddr_num, vaddr, size, vaddr_num)) - { - for (int oi = 0; oi < h.overlaps_num; oi++) - { - auto& o = h.overlaps[oi]; - if (o.type == type) - { - for (int vi = 0; vi < h.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(), h.vaddr[vi], h.size[vi], o.hash[vi], new_hash); - - o.hash[vi] = new_hash; - } - } - } - } - } -} - -void GpuMemory::Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size) -{ - Core::LockGuard lock(m_mutex); - - printf("Release gpu objects:\n"); - printf("\t gpu_vaddr = 0x%016" PRIx64 "\n", vaddr); - printf("\t size = 0x%016" PRIx64 "\n", size); - - EXIT_NOT_IMPLEMENTED(!IsAllocated(vaddr, size)); - - int index = 0; - for (auto& a: m_allocated) - { - if (a.vaddr == vaddr && a.size == size) - { - m_allocated.RemoveAt(index); - break; - } - index++; - } - - EXIT_NOT_IMPLEMENTED(IsAllocated(vaddr, size)); - - for (auto& h: m_objects) - { - for (int vi = 0; vi < h.vaddr_num; vi++) - { - if (!h.free && (h.vaddr[vi] >= vaddr && h.vaddr[vi] < vaddr + size)) - { - Free(ctx, h); - break; - } - } - } -} - -void GpuMemory::Free(GraphicContext* ctx, Object& h) -{ - for (int oi = 0; oi < h.overlaps_num; oi++) - { - auto& o = h.overlaps[oi]; - - EXIT_IF(o.delete_func == nullptr); - - if (o.delete_func != nullptr) - { - for (int vi = 0; vi < h.vaddr_num; vi++) - { - printf("Delete: type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", Core::EnumName(o.type).C_Str(), - h.vaddr[vi], h.size[vi]); - } - - o.delete_func(ctx, o.obj, &o.mem); - } - } - h.overlaps_num = 0; - h.free = true; - for (int vi = 0; vi < h.vaddr_num; vi++) - { - m_objects_size -= h.size[vi]; - } - h.vaddr_num = 0; -} - -void GpuMemory::FrameDone() -{ - Core::LockGuard lock(m_mutex); - - m_current_frame++; -} - -// NOLINTNEXTLINE(readability-function-cognitive-complexity) -void GpuMemory::WriteBack(GraphicContext* ctx) -{ - Core::LockGuard lock(m_mutex); - - for (auto& h: m_objects) - { - if (!h.free) - { - for (int oi = 0; oi < h.overlaps_num; oi++) - { - auto& o = h.overlaps[oi]; - if (o.in_use && /*o.use_last_frame >= m_current_frame &&*/ o.write_back_func != nullptr && !o.read_only) - { - o.write_back_func(ctx, o.obj, h.vaddr, h.size, h.vaddr_num); - - for (int vi = 0; vi < h.vaddr_num; vi++) - { - uint64_t new_hash = 0; - - if (o.check_hash) - { - new_hash = calc_hash(reinterpret_cast(h.vaddr[vi]), h.size[vi]); - } - - printf("WriteBack (GPU -> CPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 - ", old_hash = 0x%016" PRIx64 ", new_hash = 0x%016" PRIx64 "\n", - Core::EnumName(o.type).C_Str(), h.vaddr[vi], h.size[vi], o.hash[vi], new_hash); - - o.hash[vi] = new_hash; - } - - for (int oi2 = 0; oi2 < h.overlaps_num; oi2++) - { - if (oi2 != oi) - { - auto& o2 = h.overlaps[oi2]; - - bool need_update = false; - - for (int vi = 0; vi < h.vaddr_num; vi++) - { - uint64_t hash = o.hash[vi]; - - if (o2.hash[vi] != hash) - { - printf("Update (CPU -> GPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 - ", old_hash = 0x%016" PRIx64 ", new_hash = 0x%016" PRIx64 "\n", - Core::EnumName(o2.type).C_Str(), h.vaddr[vi], h.size[vi], o2.hash[vi], hash); - o2.hash[vi] = hash; - need_update = true; - } - } - - if (need_update) - { - EXIT_IF(o2.update_func == nullptr); - - o2.update_func(ctx, o2.params, o2.obj, h.vaddr, h.size, h.vaddr_num); - } - } - } - - o.in_use = false; - } - } - } - } -} - -void GpuMemory::Flush(GraphicContext* ctx) -{ - Core::LockGuard lock(m_mutex); - - for (auto& h: m_objects) - { - if (!h.free) - { - for (int oi = 0; oi < h.overlaps_num; oi++) - { - auto& o = h.overlaps[oi]; - - EXIT_IF(o.update_func == nullptr); - o.update_func(ctx, o.params, o.obj, h.vaddr, h.size, h.vaddr_num); - } - } - } -} - -void GpuMemory::DbgDump() -{ - Core::LockGuard lock(m_mutex); - - printf("--- Gpu Memory ---\n"); - - for (auto& o: m_allocated) - { - printf("Allocated block: vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", o.vaddr, o.size); - } - - printf("m_current_frame = %" PRIu64 "\n", m_current_frame); - printf("m_objects_size = %" PRIu64 "\n", m_objects_size); - - for (auto& h: m_objects) - { - if (!h.free) - { - printf("Object:\n"); - for (int vi = 0; vi < h.vaddr_num; vi++) - { - printf("\t vaddr = 0x%016" PRIx64 "\n", h.vaddr[vi]); - printf("\t size = 0x%016" PRIx64 "\n", h.size[vi]); - GpuResources::Info res_info; - if (g_gpu_resources->FindInfo(h.vaddr[vi], &res_info)) - { - printf("\t {\n"); - printf("\t\t RegisteredResource: %s\n", res_info.name.C_Str()); - printf("\t\t addr: %016" PRIx64 "\n", res_info.memory); - printf("\t\t size: %" PRIu64 "\n", res_info.size); - printf("\t\t type: %" PRIu32 "\n", res_info.type); - printf("\t\t user_data: %" PRIu64 "\n", res_info.user_data); - printf("\t }\n"); - - // EXIT_NOT_IMPLEMENTED(res_info.size != h.size[vi]); - // EXIT_NOT_IMPLEMENTED(res_info.memory != h.vaddr[vi]); - } - } - printf("\t overlaps_num = %d\n", h.overlaps_num); - for (int oi = 0; oi < h.overlaps_num; oi++) - { - auto& o = h.overlaps[oi]; - printf("\t [%d] type = %s\n", oi, Core::EnumName(o.type).C_Str()); - for (int vi = 0; vi < h.vaddr_num; vi++) - { - printf("\t [%d] hash = 0x%016" PRIx64 "\n", oi, o.hash[vi]); - } - printf("\t [%d] vk_size = 0x%016" PRIx64 "\n", oi, o.mem.requirements.size); - printf("\t [%d] vk_align = 0x%016" PRIx64 "\n", oi, o.mem.requirements.alignment); - printf("\t [%d] vk_type = 0x%08" PRIx32 "\n", oi, o.mem.type); - printf("\t [%d] use_last_frame = %" PRIu64 "\n", oi, o.use_last_frame); - printf("\t [%d] use_num = %" PRIu64 "\n", oi, o.use_num); - printf("\t [%d] in_use = %s\n", oi, o.in_use ? "true" : "false"); - printf("\t [%d] read_only = %s\n", oi, o.read_only ? "true" : "false"); - printf("\t [%d] check_hash = %s\n", oi, o.check_hash ? "true" : "false"); - } - } - } -} - -void GpuMemoryInit() -{ - EXIT_IF(g_gpu_memory != nullptr); - EXIT_IF(g_gpu_resources != nullptr); - - g_gpu_memory = new GpuMemory; - g_gpu_resources = new GpuResources; -} - -void GpuMemorySetAllocatedRange(uint64_t vaddr, uint64_t size) -{ - EXIT_IF(g_gpu_memory == nullptr); - - g_gpu_memory->SetAllocatedRange(vaddr, size); -} - -void GpuMemoryFree(GraphicContext* ctx, uint64_t vaddr, uint64_t size) -{ - EXIT_IF(g_gpu_memory == nullptr); - EXIT_IF(ctx == nullptr); - - g_gpu_memory->Free(ctx, vaddr, size); -} - -void* GpuMemoryGetObject(GraphicContext* ctx, uint64_t vaddr, uint64_t size, const GpuObject& info) -{ - EXIT_IF(g_gpu_memory == nullptr); - EXIT_IF(ctx == nullptr); - - return g_gpu_memory->GetObject(ctx, &vaddr, &size, 1, info); -} - -void* GpuMemoryGetObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info) -{ - EXIT_IF(g_gpu_memory == nullptr); - EXIT_IF(ctx == nullptr); - - return g_gpu_memory->GetObject(ctx, vaddr, size, vaddr_num, info); -} - -void GpuMemoryResetHash(GraphicContext* ctx, uint64_t vaddr, uint64_t size, GpuMemoryObjectType type) -{ - EXIT_IF(g_gpu_memory == nullptr); - EXIT_IF(ctx == nullptr); - - g_gpu_memory->ResetHash(ctx, &vaddr, &size, 1, type); -} - -void GpuMemoryDbgDump() -{ - EXIT_IF(g_gpu_memory == nullptr); - - g_gpu_memory->DbgDump(); -} - -void GpuMemoryFlush(GraphicContext* ctx) -{ - EXIT_IF(g_gpu_memory == nullptr); - EXIT_IF(ctx == nullptr); - - // update vulkan objects after CPU-drawing - g_gpu_memory->Flush(ctx); -} - -void GpuMemoryFrameDone() -{ - EXIT_IF(g_gpu_memory == nullptr); - - g_gpu_memory->FrameDone(); -} - -void GpuMemoryWriteBack(GraphicContext* ctx) -{ - EXIT_IF(g_gpu_memory == nullptr); - EXIT_IF(ctx == nullptr); - - // update CPU memory after GPU-drawing - g_gpu_memory->WriteBack(ctx); -} - -bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* mem) -{ - static std::atomic seq = 0; - - EXIT_IF(ctx == nullptr); - EXIT_IF(mem == nullptr); - EXIT_IF(mem->memory != nullptr); - EXIT_IF(mem->requirements.size == 0); - - VkPhysicalDeviceMemoryProperties memory_properties {}; - vkGetPhysicalDeviceMemoryProperties(ctx->physical_device, &memory_properties); - - uint32_t index = 0; - for (; index < memory_properties.memoryTypeCount; index++) - { - if ((mem->requirements.memoryTypeBits & (static_cast(1) << index)) != 0 && - (memory_properties.memoryTypes[index].propertyFlags & mem->property) == mem->property) - { - break; - } - } - - mem->type = index; - mem->offset = 0; - - VkMemoryAllocateInfo alloc_info {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.pNext = nullptr; - alloc_info.allocationSize = mem->requirements.size; - alloc_info.memoryTypeIndex = index; - - mem->unique_id = ++seq; - - return (vkAllocateMemory(ctx->device, &alloc_info, nullptr, &mem->memory) == VK_SUCCESS); -} - -void VulkanFree(GraphicContext* ctx, VulkanMemory* mem) -{ - EXIT_IF(ctx == nullptr); - EXIT_IF(mem == nullptr); - - vkFreeMemory(ctx->device, mem->memory, nullptr); - - mem->memory = nullptr; -} - -void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* mem, void** data) -{ - EXIT_IF(ctx == nullptr); - EXIT_IF(mem == nullptr); - EXIT_IF(data == nullptr); - - vkMapMemory(ctx->device, mem->memory, mem->offset, mem->requirements.size, 0, data); -} - -void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* mem) -{ - EXIT_IF(ctx == nullptr); - EXIT_IF(mem == nullptr); - - vkUnmapMemory(ctx->device, mem->memory); -} - -void VulkanBindImageMemory(GraphicContext* ctx, TextureVulkanImage* image, VulkanMemory* mem) -{ - EXIT_IF(ctx == nullptr); - EXIT_IF(mem == nullptr); - EXIT_IF(image == nullptr); - - vkBindImageMemory(ctx->device, image->image, mem->memory, mem->offset); -} - -void VulkanBindImageMemory(GraphicContext* ctx, VideoOutVulkanImage* image, VulkanMemory* mem) -{ - EXIT_IF(ctx == nullptr); - EXIT_IF(mem == nullptr); - EXIT_IF(image == nullptr); - - vkBindImageMemory(ctx->device, image->image, mem->memory, mem->offset); -} - -void VulkanBindImageMemory(GraphicContext* ctx, DepthStencilVulkanImage* image, VulkanMemory* mem) -{ - EXIT_IF(ctx == nullptr); - EXIT_IF(mem == nullptr); - EXIT_IF(image == nullptr); - - vkBindImageMemory(ctx->device, image->image, mem->memory, mem->offset); -} - -void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* mem) -{ - EXIT_IF(ctx == nullptr); - EXIT_IF(mem == nullptr); - EXIT_IF(buffer == nullptr); - - vkBindBufferMemory(ctx->device, buffer->buffer, mem->memory, mem->offset); -} - -void GpuMemoryRegisterOwner(uint32_t* owner_handle, const char* name) -{ - EXIT_IF(g_gpu_resources == nullptr); - EXIT_IF(owner_handle == nullptr); - EXIT_IF(name == nullptr); - - *owner_handle = g_gpu_resources->AddOwner(String::FromUtf8(name)); -} - -void GpuMemoryRegisterResource(uint32_t* resource_handle, uint32_t owner_handle, const void* memory, size_t size, const char* name, - uint32_t type, uint64_t user_data) -{ - EXIT_IF(g_gpu_resources == nullptr); - EXIT_IF(resource_handle == nullptr); - EXIT_IF(name == nullptr); - - *resource_handle = - g_gpu_resources->AddResource(owner_handle, reinterpret_cast(memory), size, String::FromUtf8(name), type, user_data); -} - -void GpuMemoryUnregisterAllResourcesForOwner(uint32_t owner_handle) -{ - EXIT_IF(g_gpu_resources == nullptr); - - g_gpu_resources->DeleteResources(owner_handle); -} - -void GpuMemoryUnregisterOwnerAndResources(uint32_t owner_handle) -{ - EXIT_IF(g_gpu_resources == nullptr); - - g_gpu_resources->DeleteOwner(owner_handle); -} - -void GpuMemoryUnregisterResource(uint32_t resource_handle) -{ - EXIT_IF(g_gpu_resources == nullptr); - - g_gpu_resources->DeleteResource(resource_handle); -} - -} // namespace Kyty::Libs::Graphics - -#endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Graphics/Graphics.cpp b/source/emulator/src/Graphics/Graphics.cpp index 52ea2cb..f3e9bc5 100644 --- a/source/emulator/src/Graphics/Graphics.cpp +++ b/source/emulator/src/Graphics/Graphics.cpp @@ -5,11 +5,11 @@ #include "Kyty/Core/String.h" #include "Emulator/Config.h" -#include "Emulator/Graphics/GpuMemory.h" #include "Emulator/Graphics/GraphicsRender.h" #include "Emulator/Graphics/GraphicsRun.h" #include "Emulator/Graphics/HardwareContext.h" -#include "Emulator/Graphics/Label.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" +#include "Emulator/Graphics/Objects/Label.h" #include "Emulator/Graphics/Pm4.h" #include "Emulator/Graphics/Tile.h" #include "Emulator/Graphics/VideoOut.h" diff --git a/source/emulator/src/Graphics/GraphicsRender.cpp b/source/emulator/src/Graphics/GraphicsRender.cpp index 6528c71..ec3f58e 100644 --- a/source/emulator/src/Graphics/GraphicsRender.cpp +++ b/source/emulator/src/Graphics/GraphicsRender.cpp @@ -6,20 +6,21 @@ #include "Kyty/Math/Rand.h" #include "Emulator/Config.h" -#include "Emulator/Graphics/DepthStencilBuffer.h" -#include "Emulator/Graphics/GpuMemory.h" #include "Emulator/Graphics/GraphicContext.h" #include "Emulator/Graphics/HardwareContext.h" -#include "Emulator/Graphics/IndexBuffer.h" -#include "Emulator/Graphics/Label.h" +#include "Emulator/Graphics/Objects/DepthStencilBuffer.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" +#include "Emulator/Graphics/Objects/IndexBuffer.h" +#include "Emulator/Graphics/Objects/Label.h" +#include "Emulator/Graphics/Objects/RenderTexture.h" +#include "Emulator/Graphics/Objects/StorageBuffer.h" +#include "Emulator/Graphics/Objects/Texture.h" +#include "Emulator/Graphics/Objects/VertexBuffer.h" +#include "Emulator/Graphics/Objects/VideoOutBuffer.h" #include "Emulator/Graphics/Shader.h" -#include "Emulator/Graphics/StorageBuffer.h" -#include "Emulator/Graphics/Texture.h" #include "Emulator/Graphics/Tile.h" #include "Emulator/Graphics/Utils.h" -#include "Emulator/Graphics/VertexBuffer.h" #include "Emulator/Graphics/VideoOut.h" -#include "Emulator/Graphics/VideoOutBuffer.h" #include "Emulator/Graphics/Window.h" #include "Emulator/Kernel/EventQueue.h" #include "Emulator/Kernel/Pthread.h" @@ -111,7 +112,7 @@ public: void DeleteAllPipelines(); private: - static constexpr uint32_t MAX_PIPELINES = 16; + static constexpr uint32_t MAX_PIPELINES = 32; struct Pipeline { @@ -168,11 +169,10 @@ public: void Free(VulkanDescriptorSet* set); VulkanDescriptorSet* GetDescriptor(Stage stage, int storage_buffers_num, VulkanBuffer** storage_buffers, int textures2d_sampled_num, - TextureVulkanImage** textures2d_sampled, int textures2d_storage_num, - TextureVulkanImage** textures2d_storage, int samplers_num, uint64_t* samplers, int gds_buffers_num, - VulkanBuffer** gds_buffers); + VulkanImage** textures2d_sampled, int textures2d_storage_num, VulkanImage** textures2d_storage, + int samplers_num, uint64_t* samplers, int gds_buffers_num, VulkanBuffer** gds_buffers); void FreeDescriptor(VulkanBuffer* buffer); - void FreeDescriptor(TextureVulkanImage* image); + void FreeDescriptor(VulkanImage* image); private: struct Set @@ -241,8 +241,8 @@ public: KYTY_CLASS_NO_COPY(FramebufferCache); VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* color, RenderDepthInfo* depth); - void FreeFramebuffer(VideoOutVulkanImage* image); - void FreeFramebuffer(DepthStencilVulkanImage* image); + void FreeFramebufferByColor(VulkanImage* image); + void FreeFramebufferByDepth(DepthStencilVulkanImage* image); private: VideoOutVulkanImage* CreateDummyBuffer(VkFormat format, uint32_t width, uint32_t height); @@ -349,13 +349,25 @@ struct RenderDepthInfo VkStencilOpState stencil_front = {}; VkStencilOpState stencil_back = {}; DepthStencilVulkanImage* vulkan_buffer = nullptr; + uint64_t vaddr[3] = {}; + uint64_t size[3] = {}; + int vaddr_num = 0; +}; + +enum class RenderColorType +{ + NoColorOutput, + DisplayBuffer, + OffscreenBuffer, + RenderTexture, }; struct RenderColorInfo { - VideoOutVulkanImage* vulkan_buffer = nullptr; - uint64_t base_addr = 0; - uint64_t buffer_size = 0; + RenderColorType type = RenderColorType::NoColorOutput; + VulkanImage* vulkan_buffer = nullptr; + uint64_t base_addr = 0; + uint64_t buffer_size = 0; }; class CommandPool @@ -550,7 +562,7 @@ static void z_check(const DepthRenderTarget& z) EXIT_NOT_IMPLEMENTED(z.z_info.format != 0x00000003); EXIT_NOT_IMPLEMENTED(z.z_info.tile_mode_index != (Config::IsNeo() ? 0x00000002 : 0)); EXIT_NOT_IMPLEMENTED(z.z_info.num_samples != 0x00000000); - EXIT_NOT_IMPLEMENTED(z.z_info.tile_surface_enable != true); + // EXIT_NOT_IMPLEMENTED(z.z_info.tile_surface_enable != true); EXIT_NOT_IMPLEMENTED(z.z_info.expclear_enabled != false); EXIT_NOT_IMPLEMENTED(z.z_info.zrange_precision != 0x00000001); } @@ -594,11 +606,11 @@ static void z_check(const DepthRenderTarget& z) EXIT_NOT_IMPLEMENTED(z.z_write_base_addr == 0); EXIT_NOT_IMPLEMENTED(z.stencil_info.format != 0 && z.stencil_write_base_addr == 0); // EXIT_NOT_IMPLEMENTED(z.pitch_div8_minus1 != 0x000000ff); - EXIT_NOT_IMPLEMENTED(z.height_div8_minus1 != 0x0000008f); + // EXIT_NOT_IMPLEMENTED(z.height_div8_minus1 != 0x0000008f); // EXIT_NOT_IMPLEMENTED(z.slice_div64_minus1 != 0x00008fff); - EXIT_NOT_IMPLEMENTED(z.htile_data_base_addr == 0); - EXIT_NOT_IMPLEMENTED(z.width != 0x00000780); - EXIT_NOT_IMPLEMENTED(z.height != 0x00000438); + // EXIT_NOT_IMPLEMENTED(z.htile_data_base_addr == 0); + // EXIT_NOT_IMPLEMENTED(z.width != 0x00000780); + // EXIT_NOT_IMPLEMENTED(z.height != 0x00000438); } } @@ -1142,7 +1154,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* color, R (color->vulkan_buffer->extent.width != depth->vulkan_buffer->extent.width || color->vulkan_buffer->extent.height != depth->vulkan_buffer->extent.height)); - VideoOutVulkanImage* vulkan_buffer = + VulkanImage* vulkan_buffer = (with_color ? color->vulkan_buffer : CreateDummyBuffer(VK_FORMAT_B8G8R8A8_SRGB, depth->vulkan_buffer->extent.width, depth->vulkan_buffer->extent.height)); @@ -1247,7 +1259,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* color, R return framebuffer; } -void FramebufferCache::FreeFramebuffer(VideoOutVulkanImage* image) +void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) { EXIT_IF(g_render_ctx == nullptr); EXIT_IF(image == nullptr); @@ -1277,7 +1289,7 @@ void FramebufferCache::FreeFramebuffer(VideoOutVulkanImage* image) } } -void FramebufferCache::FreeFramebuffer(DepthStencilVulkanImage* image) +void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage* image) { EXIT_IF(g_render_ctx == nullptr); EXIT_IF(image == nullptr); @@ -1328,6 +1340,7 @@ VideoOutVulkanImage* FramebufferCache::CreateDummyBuffer(VkFormat format, uint32 vk_obj->format = format; vk_obj->image = nullptr; vk_obj->image_view = nullptr; + vk_obj->layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageCreateInfo image_info {}; image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -1341,7 +1354,7 @@ VideoOutVulkanImage* FramebufferCache::CreateDummyBuffer(VkFormat format, uint32 image_info.arrayLayers = 1; image_info.format = vk_obj->format; image_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_info.initialLayout = vk_obj->layout; image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_info.samples = VK_SAMPLE_COUNT_1_BIT; @@ -2460,8 +2473,8 @@ 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, TextureVulkanImage** textures2d_sampled, - int textures2d_storage_num, TextureVulkanImage** textures2d_storage, int samplers_num, + 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) { EXIT_IF(storage_buffers_num < 0 || storage_buffers_num > BUFFERS_MAX); @@ -2736,7 +2749,7 @@ void DescriptorCache::FreeDescriptor(VulkanBuffer* buffer) } } -void DescriptorCache::FreeDescriptor(TextureVulkanImage* image) +void DescriptorCache::FreeDescriptor(VulkanImage* image) { EXIT_IF(image == nullptr); @@ -2790,12 +2803,17 @@ VkDescriptorSetLayout DescriptorCache::GetDescriptorSetLayout(Stage stage, int s void DeleteFramebuffer(VideoOutVulkanImage* image) { - g_render_ctx->GetFramebufferCache()->FreeFramebuffer(image); + g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image); +} + +void DeleteFramebuffer(RenderTextureVulkanImage* image) +{ + g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image); } void DeleteFramebuffer(DepthStencilVulkanImage* image) { - g_render_ctx->GetFramebufferCache()->FreeFramebuffer(image); + g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth(image); } void DeleteDescriptor(VulkanBuffer* buffer) @@ -2808,6 +2826,11 @@ void DeleteDescriptor(TextureVulkanImage* image) g_render_ctx->GetDescriptorCache()->FreeDescriptor(image); } +void DeleteDescriptor(RenderTextureVulkanImage* image) +{ + g_render_ctx->GetDescriptorCache()->FreeDescriptor(image); +} + static void FindRenderDepthInfo(const HardwareContext& hw, RenderDepthInfo* r) { EXIT_IF(r == nullptr); @@ -2817,17 +2840,33 @@ static void FindRenderDepthInfo(const HardwareContext& hw, RenderDepthInfo* r) const auto& rc = hw.GetRenderControl(); const auto& dc = hw.GetDepthControl(); + uint32_t size = 0; uint32_t stencil_size = 0; uint32_t htile_size = 0; uint32_t depth_size = 0; uint32_t pitch = 0; + if (z.z_info.format == 3) + { + size = (z.slice_div64_minus1 + 1) * 64 * 4; + } else if (z.z_info.format == 1) + { + size = (z.slice_div64_minus1 + 1) * 64 * 2; + } + bool htile = z.z_info.tile_surface_enable; TileGetDepthSize(z.width, z.height, z.z_info.format, z.stencil_info.format, htile, neo, &stencil_size, &htile_size, &depth_size, &pitch); - EXIT_NOT_IMPLEMENTED(pitch != 0 && (z.pitch_div8_minus1 + 1) * 8 != pitch); + if (pitch == 0) + { + depth_size = size; + } else + { + EXIT_NOT_IMPLEMENTED(depth_size != size); + EXIT_NOT_IMPLEMENTED((z.pitch_div8_minus1 + 1) * 8 != pitch); + } switch (z.z_info.format * 2 + z.stencil_info.format) { @@ -2877,117 +2916,170 @@ static void FindRenderDepthInfo(const HardwareContext& hw, RenderDepthInfo* r) { DepthStencilBufferObject vulkan_buffer_info(r->format, r->width, r->height, htile, neo); - uint64_t vaddr[3] = {}; - uint64_t size[3] = {}; - int vaddr_num = 0; + r->vaddr_num = 0; if (r->depth_buffer_size > 0) { - vaddr[vaddr_num] = r->depth_buffer_vaddr; - size[vaddr_num] = r->depth_buffer_size; - vaddr_num++; + r->vaddr[r->vaddr_num] = r->depth_buffer_vaddr; + r->size[r->vaddr_num] = r->depth_buffer_size; + r->vaddr_num++; } if (r->stencil_buffer_size > 0) { - vaddr[vaddr_num] = r->stencil_buffer_vaddr; - size[vaddr_num] = r->stencil_buffer_size; - vaddr_num++; + r->vaddr[r->vaddr_num] = r->stencil_buffer_vaddr; + r->size[r->vaddr_num] = r->stencil_buffer_size; + r->vaddr_num++; } if (r->htile_buffer_size > 0) { - vaddr[vaddr_num] = r->htile_buffer_vaddr; - size[vaddr_num] = r->htile_buffer_size; - vaddr_num++; + r->vaddr[r->vaddr_num] = r->htile_buffer_vaddr; + r->size[r->vaddr_num] = r->htile_buffer_size; + r->vaddr_num++; } - EXIT_NOT_IMPLEMENTED(vaddr_num == 0); + EXIT_NOT_IMPLEMENTED(r->vaddr_num == 0); r->vulkan_buffer = static_cast( - GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), vaddr, size, vaddr_num, vulkan_buffer_info)); + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), r->vaddr, r->size, r->vaddr_num, vulkan_buffer_info)); EXIT_NOT_IMPLEMENTED(r->vulkan_buffer == nullptr); } } +// NOLINTNEXTLINE(readability-function-cognitive-complexity) static void FindRenderColorInfo(const HardwareContext& hw, RenderColorInfo* r) { EXIT_IF(r == nullptr); - const auto& rt = hw.GetRenderTargets(0); + const auto& rt = hw.GetRenderTargets(0); + auto mask = hw.GetRenderTargetMask(); - if (rt.base_addr != 0) - { - auto width = rt.width; - auto height = rt.height; - auto pitch = (rt.pitch_div8_minus1 + 1) * 8; - auto size = (rt.slice_div64_minus1 + 1) * 64 * 4; - bool tile = false; - uint32_t format = 0; - bool render_to_texture = false; - - if (rt.tile_mode == 0x8) - { - tile = false; - } else if (rt.tile_mode == 0xa) - { - tile = true; - } else if (rt.tile_mode == 0xd) - { - tile = true; - render_to_texture = true; - } else - { - EXIT("unknown tile mode: %u\n", rt.tile_mode); - } - - if (render_to_texture) - { - EXIT("not implemented"); - } else - { - if (rt.format == 0xa && rt.channel_type == 0x6 && rt.channel_order == 0x1) - { - format = 0x80000000; - } else - { - EXIT("unknown format"); - } - - auto video_image = VideoOut::VideoOutGetImage(rt.base_addr); - if (video_image.image == nullptr) - { - // Offscreen buffer - VideoOutBufferObject vulkan_buffer_info(format, width, height, tile, Config::IsNeo(), pitch); - auto* buffer_vulkan = static_cast( - Graphics::GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), rt.base_addr, size, vulkan_buffer_info)); - EXIT_NOT_IMPLEMENTED(buffer_vulkan == nullptr); - r->base_addr = rt.base_addr; - r->vulkan_buffer = buffer_vulkan; - r->buffer_size = size; - } else - { - // Display buffer - EXIT_NOT_IMPLEMENTED(video_image.buffer_size != size); - EXIT_NOT_IMPLEMENTED(video_image.buffer_pitch != pitch); - r->base_addr = rt.base_addr; - r->vulkan_buffer = video_image.image; - r->buffer_size = video_image.buffer_size; - } - } - } else + if (rt.base_addr == 0 || mask == 0) { // No color output + r->type = RenderColorType::NoColorOutput; r->base_addr = 0; r->vulkan_buffer = nullptr; r->buffer_size = 0; + return; + } + + auto width = rt.width; + auto height = rt.height; + auto pitch = (rt.pitch_div8_minus1 + 1) * 8; + auto size = (rt.slice_div64_minus1 + 1) * 64 * 4; + bool tile = false; + uint32_t format = 0; + bool render_to_texture = false; + + if (rt.tile_mode == 0x8) + { + tile = false; + } else if (rt.tile_mode == 0xa) + { + tile = true; + } else if (rt.tile_mode == 0xd || rt.tile_mode == 0xe) + { + tile = true; + render_to_texture = true; + } else + { + EXIT("unknown tile mode: %u\n", rt.tile_mode); + } + + if (render_to_texture) + { + if (rt.format == 0xa && rt.channel_type == 0x0 && rt.channel_order == 0x0) + { + // Render to texture + RenderTextureObject vulkan_buffer_info(RenderTextureFormat::R8G8B8A8Unorm, width, height, tile, rt.neo_mode, pitch); + auto* buffer_vulkan = static_cast( + Graphics::GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), rt.base_addr, size, vulkan_buffer_info)); + EXIT_NOT_IMPLEMENTED(buffer_vulkan == nullptr); + r->type = RenderColorType::RenderTexture; + r->base_addr = rt.base_addr; + r->vulkan_buffer = buffer_vulkan; + r->buffer_size = size; + } else + { + EXIT("unknown format"); + } + } else + { + if (rt.format == 0xa && rt.channel_type == 0x6 && rt.channel_order == 0x1) + { + format = 0x80000000; + } else + { + EXIT("unknown format"); + } + + auto video_image = VideoOut::VideoOutGetImage(rt.base_addr); + if (video_image.image == nullptr) + { + // Offscreen buffer + VideoOutBufferObject vulkan_buffer_info(format, width, height, tile, Config::IsNeo(), pitch); + auto* buffer_vulkan = static_cast( + Graphics::GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), rt.base_addr, size, vulkan_buffer_info)); + EXIT_NOT_IMPLEMENTED(buffer_vulkan == nullptr); + r->type = RenderColorType::OffscreenBuffer; + r->base_addr = rt.base_addr; + r->vulkan_buffer = buffer_vulkan; + r->buffer_size = size; + } else + { + // Display buffer + EXIT_NOT_IMPLEMENTED(video_image.buffer_size != size); + EXIT_NOT_IMPLEMENTED(video_image.buffer_pitch != pitch); + r->type = RenderColorType::DisplayBuffer; + r->base_addr = rt.base_addr; + r->vulkan_buffer = video_image.image; + r->buffer_size = video_image.buffer_size; + } } } static void InvalidateMemoryObject(const RenderColorInfo& r) { - GpuMemoryResetHash(g_render_ctx->GetGraphicCtx(), r.base_addr, r.buffer_size, GpuMemoryObjectType::VideoOutBuffer); + bool with_color = (r.vulkan_buffer != nullptr); + + if (with_color) + { + if (r.type == RenderColorType::RenderTexture) + { + GpuMemoryResetHash(g_render_ctx->GetGraphicCtx(), &r.base_addr, &r.buffer_size, 1, GpuMemoryObjectType::RenderTexture); + } else if (r.type == RenderColorType::DisplayBuffer || r.type == RenderColorType::OffscreenBuffer) + { + GpuMemoryResetHash(g_render_ctx->GetGraphicCtx(), &r.base_addr, &r.buffer_size, 1, GpuMemoryObjectType::VideoOutBuffer); + } + } +} + +static void InvalidateMemoryObject(const RenderDepthInfo& r) +{ + bool with_depth = (r.format != VK_FORMAT_UNDEFINED && r.vulkan_buffer != nullptr); + + if (with_depth) + { + GpuMemoryResetHash(g_render_ctx->GetGraphicCtx(), r.vaddr, r.size, r.vaddr_num, GpuMemoryObjectType::DepthStencilBuffer); + } +} + +static RenderTextureVulkanImage* FindRenderTexture(uint64_t vaddr, uint64_t size) +{ + auto objects = GpuMemoryFindObjects(vaddr, size); + + for (const auto& obj: objects) + { + if (obj.type == GpuMemoryObjectType::RenderTexture) + { + return static_cast(obj.obj); + } + } + + return nullptr; } static void PrepareStorageBuffers(const ShaderStorageResources& storage_buffers, VulkanBuffer** buffers, uint32_t** sgprs) @@ -3026,7 +3118,7 @@ static void PrepareStorageBuffers(const ShaderStorageResources& storage_buffers, StorageBufferGpuObject buf_info(stride, num_records, read_only); - auto* buf = static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), addr, size, buf_info)); + auto* buf = static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, buf_info)); EXIT_NOT_IMPLEMENTED(buf == nullptr); @@ -3046,7 +3138,7 @@ static void PrepareStorageBuffers(const ShaderStorageResources& storage_buffers, } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -static void PrepareTextures(const ShaderTextureResources& textures, TextureVulkanImage** images, uint32_t** sgprs, bool with_sampler) +static void PrepareTextures(const ShaderTextureResources& textures, VulkanImage** images, uint32_t** sgprs, bool with_sampler) { EXIT_IF(images == nullptr); EXIT_IF(sgprs == nullptr); @@ -3059,7 +3151,7 @@ static void PrepareTextures(const ShaderTextureResources& textures, TextureVulka EXIT_NOT_IMPLEMENTED(r.Base() == 0); EXIT_NOT_IMPLEMENTED(r.MinLod() != 0); EXIT_NOT_IMPLEMENTED(r.Dfmt() != 10 && r.Dfmt() != 37); - EXIT_NOT_IMPLEMENTED(r.Nfmt() != 9); + EXIT_NOT_IMPLEMENTED(r.Nfmt() != 9 && r.Nfmt() != 0); // EXIT_NOT_IMPLEMENTED(r.Width() != 511); // EXIT_NOT_IMPLEMENTED(r.Height() != 511); EXIT_NOT_IMPLEMENTED(r.PerfMod() != 7 && r.PerfMod() != 0); @@ -3070,7 +3162,7 @@ static void PrepareTextures(const ShaderTextureResources& textures, TextureVulka // EXIT_NOT_IMPLEMENTED(r.DstSelW() != 7); EXIT_NOT_IMPLEMENTED(r.BaseLevel() != 0); EXIT_NOT_IMPLEMENTED(r.LastLevel() != 0 && r.LastLevel() != 9); - EXIT_NOT_IMPLEMENTED(!(r.TilingIdx() == 8 || r.TilingIdx() == 13)); + EXIT_NOT_IMPLEMENTED(!(r.TilingIdx() == 8 || r.TilingIdx() == 13 || r.TilingIdx() == 14)); EXIT_NOT_IMPLEMENTED(!(r.LastLevel() == 0 && r.Pow2Pad() == false) && !(r.LastLevel() == 9 && r.Pow2Pad() == true)); EXIT_NOT_IMPLEMENTED(r.Type() != 9); EXIT_NOT_IMPLEMENTED(r.Depth() != 0); @@ -3089,17 +3181,22 @@ static void PrepareTextures(const ShaderTextureResources& textures, TextureVulka auto height = r.Height() + 1; auto pitch = r.Pitch() + 1; auto levels = r.LastLevel() - r.BaseLevel() + 1; - bool tile = (r.TilingIdx() != 8); + auto tile = r.TilingIdx(); uint32_t swizzle = static_cast(r.DstSelX()) | (static_cast(r.DstSelY()) << 8u) | (static_cast(r.DstSelZ()) << 16u) | (static_cast(r.DstSelW()) << 24u); TileGetTextureSize(r.Dfmt(), r.Nfmt(), width, height, pitch, levels, tile, neo, &size, nullptr, nullptr, nullptr); EXIT_NOT_IMPLEMENTED(size == 0); - 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)); + VulkanImage* tex = FindRenderTexture(addr, size); - auto* tex = static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), addr, size, vulkan_texture_info)); + 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)); + + tex = static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, vulkan_texture_info)); + } EXIT_NOT_IMPLEMENTED(tex == nullptr); @@ -3205,11 +3302,11 @@ static void BindDescriptors(VkCommandBuffer vk_buffer, VkPipelineBindPoint pipel (!bind_params.textures2D_without_sampler && bind.textures2D.textures_num > DescriptorCache::TEXTURES_SAMPLED_MAX)); EXIT_NOT_IMPLEMENTED(bind.samplers.samplers_num > DescriptorCache::SAMPLERS_MAX); - VulkanBuffer* storage_buffers[DescriptorCache::BUFFERS_MAX]; - TextureVulkanImage* textures2d_sampled[DescriptorCache::TEXTURES_SAMPLED_MAX]; - TextureVulkanImage* textures2d_storage[DescriptorCache::TEXTURES_STORAGE_MAX]; - uint64_t samplers[DescriptorCache::SAMPLERS_MAX]; - uint32_t sgprs[DescriptorCache::PUSH_CONSTANTS_MAX]; + VulkanBuffer* storage_buffers[DescriptorCache::BUFFERS_MAX]; + VulkanImage* textures2d_sampled[DescriptorCache::TEXTURES_SAMPLED_MAX]; + VulkanImage* textures2d_storage[DescriptorCache::TEXTURES_STORAGE_MAX]; + uint64_t samplers[DescriptorCache::SAMPLERS_MAX]; + uint32_t sgprs[DescriptorCache::PUSH_CONSTANTS_MAX]; uint32_t* sgprs_ptr = sgprs; @@ -3343,7 +3440,8 @@ void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserCo uint64_t addr = b.addr; uint64_t size = b.stride * b.num_records; - auto* vertices = static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), addr, size, VertexBufferGpuObject())); + auto* vertices = + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, VertexBufferGpuObject())); VkDeviceSize offset = 0; @@ -3357,7 +3455,7 @@ void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserCo pipeline->additional_params->ps_bind, VK_SHADER_STAGE_FRAGMENT_BIT, DescriptorCache::Stage::Pixel); VulkanBuffer* indices = static_cast( - GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(index_addr), index_size, IndexBufferGpuObject())); + GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(index_addr), index_size, IndexBufferGpuObject())); EXIT_NOT_IMPLEMENTED(indices == nullptr); @@ -3368,6 +3466,7 @@ void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserCo buffer->EndRenderPass(); InvalidateMemoryObject(color_info); + InvalidateMemoryObject(depth_info); } // NOLINTNEXTLINE(readability-function-cognitive-complexity) @@ -3448,7 +3547,8 @@ void GraphicsRenderDrawIndexAuto(CommandBuffer* buffer, HardwareContext* ctx, Us uint64_t addr = b.addr; uint64_t size = b.stride * b.num_records; - auto* vertices = static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), addr, size, VertexBufferGpuObject())); + auto* vertices = + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), addr, size, VertexBufferGpuObject())); VkDeviceSize offset = 0; @@ -3479,6 +3579,7 @@ void GraphicsRenderDrawIndexAuto(CommandBuffer* buffer, HardwareContext* ctx, Us buffer->EndRenderPass(); InvalidateMemoryObject(color_info); + InvalidateMemoryObject(depth_info); } void GraphicsRenderDispatchDirect(CommandBuffer* buffer, HardwareContext* ctx, uint32_t thread_group_x, uint32_t thread_group_y, @@ -3535,6 +3636,43 @@ void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) nullptr); } +void GraphicsRenderRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size) +{ + EXIT_IF(buffer == nullptr); + EXIT_IF(buffer->IsInvalid()); + + Core::LockGuard lock(g_render_ctx->GetMutex()); + + auto* vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; + + VulkanImage* image = FindRenderTexture(vaddr, size); + + EXIT_NOT_IMPLEMENTED(image == nullptr); + EXIT_NOT_IMPLEMENTED(image->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + VkImageMemoryBarrier image_memory_barrier {}; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + image_memory_barrier.oldLayout = image->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = image->image; + image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(vk_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, + &image_memory_barrier); + + image->layout = image_memory_barrier.newLayout; +} + void GraphicsRenderWriteAtEndOfPipe(CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value) { EXIT_IF(g_render_ctx == nullptr); @@ -3547,7 +3685,7 @@ void GraphicsRenderWriteAtEndOfPipe(CommandBuffer* buffer, uint32_t* dst_gpu_add Graphics::LabelGpuObject label_info(value, nullptr, nullptr); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); LabelSet(buffer, label); } @@ -3576,7 +3714,7 @@ void GraphicsRenderWriteAtEndOfPipeGds(CommandBuffer* buffer, uint32_t* dst_gpu_ nullptr, args); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); LabelSet(buffer, label); } @@ -3593,7 +3731,7 @@ void GraphicsRenderWriteAtEndOfPipe(CommandBuffer* buffer, uint64_t* dst_gpu_add Graphics::LabelGpuObject label_info(value, nullptr, nullptr); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3623,7 +3761,7 @@ void GraphicsRenderWriteAtEndOfPipeClockCounter(CommandBuffer* buffer, uint64_t* nullptr, args); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3648,7 +3786,7 @@ void GraphicsRenderWriteAtEndOfPipeWithWriteBack(CommandBuffer* buffer, uint64_t nullptr); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3678,7 +3816,7 @@ void GraphicsRenderWriteAtEndOfPipeWithInterruptWriteBack(CommandBuffer* buffer, }); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3701,7 +3839,7 @@ void GraphicsRenderWriteAtEndOfPipeWithInterrupt(CommandBuffer* buffer, uint64_t }); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 8, label_info)); LabelSet(buffer, label); } @@ -3743,7 +3881,7 @@ void GraphicsRenderWriteAtEndOfPipeWithInterruptWriteBackFlip(CommandBuffer* buf args); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); LabelSet(buffer, label); } @@ -3776,7 +3914,7 @@ void GraphicsRenderWriteAtEndOfPipeWithFlip(CommandBuffer* buffer, uint32_t* dst nullptr, args); auto* label = - static_cast(GpuMemoryGetObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); + static_cast(GpuMemoryCreateObject(g_render_ctx->GetGraphicCtx(), reinterpret_cast(dst_gpu_addr), 4, label_info)); LabelSet(buffer, label); } @@ -4069,6 +4207,31 @@ VulkanFramebuffer* CommandBuffer::BeginRenderPass(RenderColorInfo* color, Render render_pass_info.clearValueCount = with_depth ? 2 : 1; render_pass_info.pClearValues = clears; + if (with_color && color->vulkan_buffer->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { + VkImageMemoryBarrier image_memory_barrier {}; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; + image_memory_barrier.oldLayout = color->vulkan_buffer->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + 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.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, + &image_memory_barrier); + + color->vulkan_buffer->layout = image_memory_barrier.newLayout; + } + vkCmdBeginRenderPass(buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); return framebuffer; diff --git a/source/emulator/src/Graphics/GraphicsRun.cpp b/source/emulator/src/Graphics/GraphicsRun.cpp index 0b56016..1845cbe 100644 --- a/source/emulator/src/Graphics/GraphicsRun.cpp +++ b/source/emulator/src/Graphics/GraphicsRun.cpp @@ -70,6 +70,7 @@ public: void FlipWithInterrupt(uint32_t eop_event_type, uint32_t cache_action, void* dst_gpu_addr, uint32_t value); void WriteBack(); void MemoryBarrier(); + void RenderTextureBarrier(uint64_t vaddr, uint64_t size); void DispatchDirect(uint32_t thread_group_x, uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode); void WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index); void TriggerEvent(uint32_t event_type, uint32_t event_index); @@ -1109,6 +1110,15 @@ void CommandProcessor::MemoryBarrier() GraphicsRenderMemoryBarrier(m_buffer[m_current_buffer]); } +void CommandProcessor::RenderTextureBarrier(uint64_t vaddr, uint64_t size) +{ + Core::LockGuard lock(m_mutex); + + EXIT_IF(m_current_buffer < 0 || m_current_buffer >= VK_BUFFERS_NUM); + + GraphicsRenderRenderTextureBarrier(m_buffer[m_current_buffer], vaddr, size); +} + void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index) { Core::LockGuard lock(m_mutex); @@ -1117,7 +1127,7 @@ void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index) printf("\t event_type = 0x%08" PRIx32 "\n", event_type); printf("\t event_index = 0x%08" PRIx32 "\n", event_index); - if (event_type == 0x00000016 && event_index == 0x00000007) + if ((event_type == 0x00000016 || event_type == 0x00000031) && event_index == 0x00000007) { MemoryBarrier(); } else @@ -2192,25 +2202,42 @@ KYTY_CP_OP_PARSER(cp_op_acquire_mem) uint32_t stall_mode = buffer[0] >> 31u; uint32_t cache_action = buffer[0] & 0x7fffffffu; - uint32_t size_lo = buffer[1]; + uint64_t size_lo = buffer[1]; uint32_t size_hi = buffer[2]; - uint32_t base_lo = buffer[3]; + uint64_t base_lo = buffer[3]; uint32_t base_hi = buffer[4]; uint32_t poll = buffer[5]; EXIT_NOT_IMPLEMENTED(stall_mode != 1); - EXIT_NOT_IMPLEMENTED(cache_action != 0x00C40000 && cache_action != 0x00400000); - EXIT_NOT_IMPLEMENTED(size_lo != 1); EXIT_NOT_IMPLEMENTED(size_hi != 0); - EXIT_NOT_IMPLEMENTED(base_lo != 0); EXIT_NOT_IMPLEMENTED(base_hi != 0); EXIT_NOT_IMPLEMENTED(poll != 10); - cp->MemoryBarrier(); - - if (cache_action == 0x00C40000) + switch (cache_action) { - cp->WriteBack(); + case 0x02003fc0: + { + EXIT_NOT_IMPLEMENTED(size_lo == 0); + EXIT_NOT_IMPLEMENTED(base_lo == 0); + cp->RenderTextureBarrier(base_lo << 8u, size_lo << 8u); + } + break; + case 0x00C40000: + { + EXIT_NOT_IMPLEMENTED(size_lo != 1); + EXIT_NOT_IMPLEMENTED(base_lo != 0); + cp->MemoryBarrier(); + cp->WriteBack(); + } + break; + case 0x00400000: + { + EXIT_NOT_IMPLEMENTED(size_lo != 1); + EXIT_NOT_IMPLEMENTED(base_lo != 0); + cp->MemoryBarrier(); + } + break; + default: EXIT("unknown barrier"); } return 6; diff --git a/source/emulator/src/Graphics/DepthStencilBuffer.cpp b/source/emulator/src/Graphics/Objects/DepthStencilBuffer.cpp similarity index 96% rename from source/emulator/src/Graphics/DepthStencilBuffer.cpp rename to source/emulator/src/Graphics/Objects/DepthStencilBuffer.cpp index c8a4dda..16d084f 100644 --- a/source/emulator/src/Graphics/DepthStencilBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/DepthStencilBuffer.cpp @@ -1,4 +1,4 @@ -#include "Emulator/Graphics/DepthStencilBuffer.h" +#include "Emulator/Graphics/Objects/DepthStencilBuffer.h" #include "Kyty/Core/DbgAssert.h" @@ -37,6 +37,7 @@ void* DepthStencilBufferObject::Create(GraphicContext* ctx, const uint64_t* vadd vk_obj->format = pixel_format; vk_obj->image = nullptr; vk_obj->image_view = nullptr; + vk_obj->layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageCreateInfo image_info {}; image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -50,7 +51,7 @@ void* DepthStencilBufferObject::Create(GraphicContext* ctx, const uint64_t* vadd image_info.arrayLayers = 1; image_info.format = vk_obj->format; image_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_info.initialLayout = vk_obj->layout; image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_info.samples = VK_SAMPLE_COUNT_1_BIT; @@ -96,7 +97,7 @@ void* DepthStencilBufferObject::Create(GraphicContext* ctx, const uint64_t* vadd EXIT_NOT_IMPLEMENTED(vk_obj->image_view == nullptr); - UtilSetImageLayoutOptimal(vk_obj); + UtilSetDepthLayoutOptimal(vk_obj); return vk_obj; } diff --git a/source/emulator/src/Graphics/Objects/GpuMemory.cpp b/source/emulator/src/Graphics/Objects/GpuMemory.cpp new file mode 100644 index 0000000..f06f3c8 --- /dev/null +++ b/source/emulator/src/Graphics/Objects/GpuMemory.cpp @@ -0,0 +1,1353 @@ +#include "Emulator/Graphics/Objects/GpuMemory.h" + +#include "Kyty/Core/Database.h" +#include "Kyty/Core/DbgAssert.h" +#include "Kyty/Core/MagicEnum.h" +#include "Kyty/Core/String.h" +#include "Kyty/Core/Threads.h" +#include "Kyty/Core/Vector.h" + +#include "Emulator/Graphics/GraphicContext.h" +#include "Emulator/Profiler.h" + +#include +#include +#include + +//#define XXH_INLINE_ALL +#include + +#ifdef KYTY_EMU_ENABLED + +namespace Kyty::Libs::Graphics { + +enum class OverlapType : uint64_t +{ + None, + Equals, + Crosses, + Contains, + IsContainedWithin, + + Max +}; + +constexpr uint64_t ObjectsRelation(GpuMemoryObjectType b, OverlapType relation, GpuMemoryObjectType a) +{ + return static_cast(a) * static_cast(GpuMemoryObjectType::Max) * static_cast(OverlapType::Max) + + static_cast(b) * static_cast(OverlapType::Max) + static_cast(relation); +} + +OverlapType GetOverlapType(uint64_t vaddr_a, uint64_t size_a, uint64_t vaddr_b, uint64_t size_b) +{ + EXIT_IF(size_a == 0 || size_b == 0); + + if (vaddr_a == vaddr_b && size_a == size_b) + { + return OverlapType::Equals; + } + + uint64_t vaddr_last_a = vaddr_a + size_a - 1; + uint64_t vaddr_last_b = vaddr_b + size_b - 1; + + auto addr_in_block = [](uint64_t block_addr, uint64_t block_size, uint64_t addr) + { return addr >= block_addr && addr < block_addr + block_size; }; + + bool a_b = addr_in_block(vaddr_a, size_a, vaddr_b); + bool a_lb = addr_in_block(vaddr_a, size_a, vaddr_last_b); + bool b_a = addr_in_block(vaddr_b, size_b, vaddr_a); + bool b_la = addr_in_block(vaddr_b, size_b, vaddr_last_a); + + if (a_b && a_lb) + { + return OverlapType::Contains; + } + + if (b_a && b_la) + { + return OverlapType::IsContainedWithin; + } + + if ((a_b && b_la) || (b_a && a_lb)) + { + return OverlapType::Crosses; + } + + return OverlapType::None; +} + +class GpuMemory +{ +public: + GpuMemory() + { + EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); + DbgInit(); + } + virtual ~GpuMemory() { KYTY_NOT_IMPLEMENTED; } + KYTY_CLASS_NO_COPY(GpuMemory); + + bool IsAllocated(uint64_t vaddr, uint64_t size); + void SetAllocatedRange(uint64_t vaddr, uint64_t size); + void Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size); + + void* CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info); + void ResetHash(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, GpuMemoryObjectType type); + void FrameDone(); + + Vector FindObjects(const uint64_t* vaddr, const uint64_t* size, int vaddr_num); + + // Sync: GPU -> CPU + void WriteBack(GraphicContext* ctx); + + // Sync: CPU -> GPU + void Flush(GraphicContext* ctx); + + void DbgInit(); + void DbgDbDump(); + void DbgDbSave(const String& file_name); + void DbgDump(); + +private: + static constexpr int OBJ_OVERLAPS_MAX = 2; + static constexpr int VADDR_BLOCKS_MAX = 3; + + struct AllocatedRange + { + uint64_t vaddr; + uint64_t size; + }; + + struct ObjectInfo + { + void* obj = nullptr; + 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; + GpuObject::update_func_t update_func = nullptr; + uint64_t use_last_frame = 0; + uint64_t use_num = 0; + bool in_use = false; + bool read_only = false; + bool check_hash = false; + VulkanMemory mem; + }; + + struct OverlappedBlock + { + OverlapType relation = OverlapType::None; + int object_id = -1; + }; + + struct Block + { + uint64_t vaddr[VADDR_BLOCKS_MAX] = {}; + uint64_t size[VADDR_BLOCKS_MAX] = {}; + int vaddr_num = 0; + }; + + struct Object + { + Block block; + ObjectInfo info; + Vector others; + bool free = true; + }; + + void Free(GraphicContext* ctx, int object_id); + + Vector FindBlocks(const uint64_t* vaddr, const uint64_t* size, int vaddr_num); + Block CreateBlock(const uint64_t* vaddr, const uint64_t* size, int vaddr_num); + void DeleteBlock(Block* b); + void Link(int id1, int id2, OverlapType rel); + + static void Update(GraphicContext* ctx, ObjectInfo& o, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, + const uint64_t* hash); + + Core::Mutex m_mutex; + + Vector m_allocated; + Vector m_objects; + uint64_t m_objects_size = 0; + uint64_t m_current_frame = 0; + + Core::Database::Connection m_db; + Core::Database::Statement* m_db_add_range = nullptr; + Core::Database::Statement* m_db_add_object = nullptr; +}; + +class GpuResources +{ +public: + struct Info + { + uint32_t owner = 0; + bool free = true; + uint64_t memory = 0; + size_t size = 0; + String name; + uint32_t type = 0; + uint64_t user_data = 0; + }; + + GpuResources() { EXIT_NOT_IMPLEMENTED(!Core::Thread::IsMainThread()); } + virtual ~GpuResources() { KYTY_NOT_IMPLEMENTED; } + KYTY_CLASS_NO_COPY(GpuResources); + + uint32_t AddOwner(const String& name); + uint32_t AddResource(uint32_t owner_handle, uint64_t memory, size_t size, const String& name, uint32_t type, uint64_t user_data); + void DeleteOwner(uint32_t owner_handle); + void DeleteResources(uint32_t owner_handle); + void DeleteResource(uint32_t resource_handle); + + bool FindInfo(uint64_t memory, Info* dst); + +private: + struct Owner + { + String name; + bool free = true; + }; + + Core::Mutex m_mutex; + + Vector m_owners; + Vector m_infos; +}; + +static GpuMemory* g_gpu_memory = nullptr; +static GpuResources* g_gpu_resources = nullptr; + +uint32_t GpuResources::AddOwner(const String& name) +{ + Core::LockGuard lock(m_mutex); + + Owner n; + n.name = name; + n.free = false; + + uint32_t index = 0; + for (auto& b: m_owners) + { + if (b.free) + { + b = n; + return index; + } + index++; + } + + m_owners.Add(n); + + return index; +} + +uint32_t GpuResources::AddResource(uint32_t owner_handle, uint64_t memory, size_t size, const String& name, uint32_t type, + uint64_t user_data) +{ + Core::LockGuard lock(m_mutex); + + EXIT_NOT_IMPLEMENTED(!m_owners.IndexValid(owner_handle)); + EXIT_NOT_IMPLEMENTED(memory == 0); + + Info info; + info.owner = owner_handle; + info.memory = memory; + info.free = false; + info.name = name; + info.size = size; + info.type = type; + info.user_data = user_data; + + uint32_t index = 0; + for (auto& i: m_infos) + { + if (i.free) + { + i = info; + return index; + } + index++; + } + + m_infos.Add(info); + + return index; +} + +void GpuResources::DeleteOwner(uint32_t owner_handle) +{ + Core::LockGuard lock(m_mutex); + + EXIT_NOT_IMPLEMENTED(!m_owners.IndexValid(owner_handle)); + + for (auto& i: m_infos) + { + if (!i.free && i.owner == owner_handle) + { + i.free = true; + } + } + + EXIT_NOT_IMPLEMENTED(m_owners[owner_handle].free); + + m_owners[owner_handle].free = true; +} + +void GpuResources::DeleteResources(uint32_t owner_handle) +{ + Core::LockGuard lock(m_mutex); + + EXIT_NOT_IMPLEMENTED(!m_owners.IndexValid(owner_handle)); + + for (auto& i: m_infos) + { + if (!i.free && i.owner == owner_handle) + { + i.free = true; + } + } +} + +void GpuResources::DeleteResource(uint32_t resource_handle) +{ + Core::LockGuard lock(m_mutex); + + EXIT_NOT_IMPLEMENTED(!m_infos.IndexValid(resource_handle)); + + EXIT_NOT_IMPLEMENTED(m_infos[resource_handle].free); + + m_infos[resource_handle].free = true; +} + +bool GpuResources::FindInfo(uint64_t memory, Info* dst) +{ + EXIT_IF(dst == nullptr); + + Core::LockGuard lock(m_mutex); + + // NOLINTNEXTLINE(readability-use-anyofallof) + for (const auto& i: m_infos) + { + if (!i.free && memory >= i.memory && memory < i.memory + i.size) + { + *dst = i; + return true; + } + } + + return false; +} + +void GpuMemory::SetAllocatedRange(uint64_t vaddr, uint64_t size) +{ + EXIT_IF(size == 0); + + EXIT_NOT_IMPLEMENTED(IsAllocated(vaddr, size)); + + Core::LockGuard lock(m_mutex); + + AllocatedRange r {}; + r.vaddr = vaddr; + r.size = size; + + m_allocated.Add(r); +} + +bool GpuMemory::IsAllocated(uint64_t vaddr, uint64_t size) +{ + EXIT_IF(size == 0); + + Core::LockGuard lock(m_mutex); + + return std::any_of(m_allocated.begin(), m_allocated.end(), + [vaddr, size](auto& r) { + return ((vaddr >= r.vaddr && vaddr < r.vaddr + r.size) || + ((vaddr + size - 1) >= r.vaddr && (vaddr + size - 1) < r.vaddr + r.size)); + }); +} + +static uint64_t calc_hash(const uint8_t* buf, uint64_t size) +{ + KYTY_PROFILER_FUNCTION(); + + return (size > 0 && buf != nullptr ? XXH64(buf, size, 0) : 0); +} + +void GpuMemory::Link(int id1, int id2, OverlapType rel) +{ + EXIT_NOT_IMPLEMENTED(rel != OverlapType::Equals); + + auto& h1 = m_objects[id1]; + EXIT_IF(h1.free); + + auto& h2 = m_objects[id2]; + EXIT_IF(h2.free); + + EXIT_NOT_IMPLEMENTED(!h1.others.IsEmpty()); + EXIT_NOT_IMPLEMENTED(!h2.others.IsEmpty()); + + h1.others.Add({rel, id2}); + h2.others.Add({rel, id1}); +} + +void GpuMemory::Update(GraphicContext* ctx, ObjectInfo& o, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const uint64_t* hash) +{ + bool need_update = false; + for (int vi = 0; vi < vaddr_num; vi++) + { + if (o.hash[vi] != hash[vi]) + { + printf("Update (CPU -> GPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", Core::EnumName(o.type).C_Str(), + vaddr[vi], size[vi]); + need_update = true; + o.hash[vi] = hash[vi]; + } + } + if (need_update) + { + EXIT_IF(o.update_func == nullptr); + o.update_func(ctx, o.params, o.obj, vaddr, size, vaddr_num); + } +} + +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +void* GpuMemory::CreateObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info) +{ + EXIT_IF(info.type == GpuMemoryObjectType::Invalid); + EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num > VADDR_BLOCKS_MAX || vaddr_num <= 0); + + Core::LockGuard lock(m_mutex); + + uint64_t hash[VADDR_BLOCKS_MAX] = {}; + + for (int vi = 0; vi < vaddr_num; vi++) + { + EXIT_IF(size[vi] == 0); + + if (info.check_hash) + { + hash[vi] = calc_hash(reinterpret_cast(vaddr[vi]), size[vi]); + } else + { + hash[vi] = 0; + } + } + + bool overlap = false; + bool delete_all = false; + + auto others = FindBlocks(vaddr, size, vaddr_num); + + if (!others.IsEmpty()) + { + for (const auto& obj: others) + { + 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)) + { + Update(ctx, o, vaddr, size, vaddr_num, hash); + + o.use_num++; + o.use_last_frame = m_current_frame; + o.in_use = true; + o.read_only = info.read_only; + o.check_hash = info.check_hash; + return o.obj; + } + } + + if (others.Size() == 1) + { + const auto& obj = others.At(0); + auto& h = m_objects[obj.object_id]; + EXIT_IF(h.free); + auto& o = h.info; + + switch (ObjectsRelation(o.type, obj.relation, info.type)) + { + case ObjectsRelation(GpuMemoryObjectType::StorageBuffer, OverlapType::Equals, GpuMemoryObjectType::RenderTexture): + case ObjectsRelation(GpuMemoryObjectType::VideoOutBuffer, OverlapType::Equals, GpuMemoryObjectType::StorageBuffer): + { + overlap = true; + break; + } + case ObjectsRelation(GpuMemoryObjectType::StorageBuffer, OverlapType::Contains, GpuMemoryObjectType::Label): + case ObjectsRelation(GpuMemoryObjectType::Label, OverlapType::Equals, GpuMemoryObjectType::Label): + { + delete_all = true; + break; + } + default: + EXIT("unknown relation: %s - %s - %s\n", Core::EnumName(o.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; + for (const auto& obj: others) + { + EXIT_NOT_IMPLEMENTED(rel != obj.relation || type != m_objects[obj.object_id].info.type); + } + + switch (ObjectsRelation(type, rel, info.type)) // NOLINT + { + case ObjectsRelation(GpuMemoryObjectType::Label, OverlapType::IsContainedWithin, GpuMemoryObjectType::StorageBuffer): + delete_all = 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()); + } + } + } + + EXIT_IF(delete_all && overlap); + + if (delete_all) + { + for (const auto& obj: others) + { + Free(ctx, obj.object_id); + } + } + + for (int vi = 0; vi < vaddr_num; vi++) + { + EXIT_NOT_IMPLEMENTED(!IsAllocated(vaddr[vi], size[vi])); + } + + ObjectInfo o {}; + + for (int i = 0; i < GpuObject::PARAMS_MAX; i++) + { + o.params[i] = info.params[i]; + } + + o.type = info.type; + o.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); + o.write_back_func = info.GetWriteBackFunc(); + o.delete_func = info.GetDeleteFunc(); + o.update_func = info.GetUpdateFunc(); + o.use_num = 1; + o.use_last_frame = m_current_frame; + o.in_use = true; + o.read_only = info.read_only; + o.check_hash = info.check_hash; + + bool updated = false; + + int index = 0; + for (auto& u: m_objects) + { + if (u.free) + { + u.free = false; + u.block = CreateBlock(vaddr, size, vaddr_num); + u.info = o; + u.others.Clear(); + updated = true; + break; + } + index++; + } + + if (!updated) + { + Object h {}; + h.block = CreateBlock(vaddr, size, vaddr_num); + h.info = o; + h.others.Clear(); + h.free = false; + m_objects.Add(h); + } + + if (overlap) + { + EXIT_NOT_IMPLEMENTED(others.Size() != 1); + + Link(index, others.At(0).object_id, others.At(0).relation); + } + + return o.obj; +} + +Vector GpuMemory::FindObjects(const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num > VADDR_BLOCKS_MAX || vaddr_num <= 0); + + Core::LockGuard lock(m_mutex); + + auto objects = FindBlocks(vaddr, size, vaddr_num); + + Vector ret; + + printf("GpuMemory::FindObjects()\n"); + + for (int i = 0; i < vaddr_num; i++) + { + printf("\t vaddr = %016" PRIx64 ", size = %016" PRIx64 "\n", vaddr[i], size[i]); + } + + for (const auto& obj: objects) + { + const auto& h = m_objects[obj.object_id]; + EXIT_IF(h.free); + printf("\t %s, %d, %s\n", Core::EnumName(obj.relation).C_Str(), obj.object_id, Core::EnumName(h.info.type).C_Str()); + if (obj.relation == OverlapType::Equals) + { + ret.Add({h.info.type, h.info.obj}); + } + } + + return ret; +} + +void GpuMemory::ResetHash(GraphicContext* /*ctx*/, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, GpuMemoryObjectType type) +{ + EXIT_IF(type == GpuMemoryObjectType::Invalid); + EXIT_IF(vaddr == nullptr || size == nullptr || vaddr_num > VADDR_BLOCKS_MAX || vaddr_num <= 0); + + Core::LockGuard lock(m_mutex); + + uint64_t new_hash = 0; + + auto object_ids = FindBlocks(vaddr, size, vaddr_num); + + if (!object_ids.IsEmpty()) + { + for (const auto& obj: object_ids) + { + EXIT_NOT_IMPLEMENTED(obj.relation != OverlapType::Equals); + + auto& h = m_objects[obj.object_id]; + EXIT_IF(h.free); + + auto& o = h.info; + if (o.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); + + o.hash[vi] = new_hash; + } + } + } + } +} + +void GpuMemory::Free(GraphicContext* ctx, uint64_t vaddr, uint64_t size) +{ + Core::LockGuard lock(m_mutex); + + printf("Release gpu objects:\n"); + printf("\t gpu_vaddr = 0x%016" PRIx64 "\n", vaddr); + printf("\t size = 0x%016" PRIx64 "\n", size); + + EXIT_NOT_IMPLEMENTED(!IsAllocated(vaddr, size)); + + int index = 0; + for (auto& a: m_allocated) + { + if (a.vaddr == vaddr && a.size == size) + { + m_allocated.RemoveAt(index); + break; + } + index++; + } + + EXIT_NOT_IMPLEMENTED(IsAllocated(vaddr, size)); + + auto object_ids = FindBlocks(&vaddr, &size, 1); + + for (const auto& obj: object_ids) + { + switch (obj.relation) + { + case OverlapType::IsContainedWithin: + case OverlapType::Crosses: Free(ctx, obj.object_id); break; + default: GpuMemoryDbgDump(); EXIT("unknown obj.relation: %s\n", Core::EnumName(obj.relation).C_Str()); + } + } +} + +void GpuMemory::Free(GraphicContext* ctx, int object_id) +{ + auto& h = m_objects[object_id]; + EXIT_IF(h.free); + auto& o = h.info; + + EXIT_IF(o.delete_func == nullptr); + + if (o.delete_func != nullptr) + { + const auto& block = h.block; + // EXIT_IF(block.free); + for (int vi = 0; vi < block.vaddr_num; vi++) + { + printf("Delete: type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", Core::EnumName(o.type).C_Str(), + block.vaddr[vi], block.size[vi]); + } + o.delete_func(ctx, o.obj, &o.mem); + } + h.free = true; + DeleteBlock(&h.block); +} + +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +Vector GpuMemory::FindBlocks(const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + EXIT_IF(vaddr_num <= 0 || vaddr_num > VADDR_BLOCKS_MAX); + EXIT_IF(vaddr == nullptr || size == nullptr); + + Vector ret; + + if (vaddr_num != 1) + { + int index = 0; + for (auto& b: m_objects) + { + if (!b.free) + { + bool equal = true; + for (int i = 0; i < vaddr_num; i++) + { + if (GetOverlapType(b.block.vaddr[i], b.block.size[i], vaddr[i], size[i]) != OverlapType::Equals) + { + equal = false; + break; + } + } + if (equal) + { + ret.Add({OverlapType::Equals, index}); + } else + { + bool cross = false; + for (int i = 0; i < vaddr_num; i++) + { + for (int j = 0; j < b.block.vaddr_num; j++) + { + if (GetOverlapType(b.block.vaddr[j], b.block.size[j], vaddr[i], size[i]) != OverlapType::None) + { + cross = true; + break; + } + } + if (cross) + { + break; + } + } + if (cross) + { + ret.Add({OverlapType::Crosses, index}); + } + } + } + index++; + } + } else + { + int index = 0; + for (auto& b: m_objects) + { + if (!b.free) + { + if (b.block.vaddr_num == 1) + { + auto type = GetOverlapType(b.block.vaddr[0], b.block.size[0], vaddr[0], size[0]); + if (type != OverlapType::None) + { + ret.Add({type, index}); + } + } else + { + for (int i = 0; i < b.block.vaddr_num; i++) + { + if (GetOverlapType(b.block.vaddr[i], b.block.size[i], vaddr[0], size[0]) != OverlapType::None) + { + ret.Add({OverlapType::Crosses, index}); + break; + } + } + } + } + index++; + } + } + return ret; +} + +GpuMemory::Block GpuMemory::CreateBlock(const uint64_t* vaddr, const uint64_t* size, int vaddr_num) +{ + EXIT_IF(vaddr_num > VADDR_BLOCKS_MAX); + EXIT_IF(vaddr == nullptr || size == nullptr); + + Block nb {}; + nb.vaddr_num = vaddr_num; + for (int vi = 0; vi < vaddr_num; vi++) + { + nb.vaddr[vi] = vaddr[vi]; + nb.size[vi] = size[vi]; + m_objects_size += size[vi]; + } + return nb; +} + +void GpuMemory::DeleteBlock(Block* b) +{ + for (int vi = 0; vi < b->vaddr_num; vi++) + { + m_objects_size -= b->size[vi]; + } +} + +void GpuMemory::FrameDone() +{ + Core::LockGuard lock(m_mutex); + + m_current_frame++; +} + +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +void GpuMemory::WriteBack(GraphicContext* ctx) +{ + Core::LockGuard lock(m_mutex); + + int index = 0; + for (auto& h: m_objects) + { + if (!h.free) + { + auto& o = h.info; + if (o.in_use && /*o.use_last_frame >= m_current_frame &&*/ o.write_back_func != nullptr && !o.read_only) + { + auto& block = h.block; + // EXIT_IF(block.free); + + o.write_back_func(ctx, o.obj, block.vaddr, block.size, block.vaddr_num); + + for (int vi = 0; vi < block.vaddr_num; vi++) + { + uint64_t new_hash = 0; + + if (o.check_hash) + { + new_hash = calc_hash(reinterpret_cast(block.vaddr[vi]), block.size[vi]); + } + + printf("WriteBack (GPU -> CPU): type = %s, vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 ", old_hash = 0x%016" PRIx64 + ", new_hash = 0x%016" PRIx64 "\n", + Core::EnumName(o.type).C_Str(), block.vaddr[vi], block.size[vi], o.hash[vi], new_hash); + + o.hash[vi] = new_hash; + } + + if (!h.others.IsEmpty()) + { + EXIT_NOT_IMPLEMENTED(h.others.Size() != 1); + EXIT_NOT_IMPLEMENTED(h.others.At(0).relation != OverlapType::Equals); + + auto& o2 = m_objects[h.others.At(0).object_id].info; + + Update(ctx, o2, block.vaddr, block.size, block.vaddr_num, o.hash); + } + + o.in_use = false; + } + } + index++; + } +} + +void GpuMemory::Flush(GraphicContext* ctx) +{ + Core::LockGuard lock(m_mutex); + + for (auto& h: m_objects) + { + if (!h.free) + { + auto& block = h.block; + // EXIT_IF(block.free); + + 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); + } + } +} + +void GpuMemory::DbgInit() +{ + EXIT_IF(!m_db.IsInvalid()); + [[maybe_unused]] bool create = m_db.CreateInMemory(); + EXIT_IF(!create); + if (!m_db.IsInvalid()) + { + m_db.Exec(R"( +CREATE TABLE [objects]( + [dump_id] INT, + [id] INTEGER PRIMARY KEY UNIQUE, + [vaddr] TEXT, + [size] TEXT, + [vaddr2] TEXT, + [size2] TEXT, + [vaddr3] TEXT, + [size3] TEXT, + [obj] TEXT, + [type] TEXT, + [param0] INT64, + [param1] INT64, + [param2] INT64, + [param3] INT64, + [param4] INT64, + [param5] INT64, + [param6] INT64, + [param7] INT64, + [other_rel] TEXT, + [other_id] INTEGER REFERENCES [objects]([id]), + [hash] TEXT, + [hash2] TEXT, + [hash3] TEXT, + [write_back_func] TEXT, + [delete_func] TEXT, + [update_func] TEXT, + [use_last_frame] INT64, + [use_num] INT64, + [in_use] BOOL, + [read_only] BOOL, + [check_hash] BOOL, + [vk_mem_size] TEXT, + [vk_mem_alignment] TEXT, + [vk_mem_memoryTypeBits] INT, + [vk_mem_property] INT, + [vk_mem_memory] TEXT, + [vk_mem_offset] INT64, + [vk_mem_type] INT, + [vk_mem_unique_id] INT64) WITHOUT ROWID; + +CREATE TABLE [ranges]( + [dump_id] INT, + [vaddr] TEXT, + [size] TEXT); +)"); + + m_db_add_range = m_db.Prepare("insert into ranges(dump_id, vaddr, size) values(:dump_id, :vaddr, :size)"); + m_db_add_object = m_db.Prepare( + "insert into objects(dump_id, id, vaddr, vaddr2, vaddr3, size, size2, size3, obj, param0, param1, param2, param3, param4, " + "param5, param6, param7, type, hash, hash2, " + "hash3, other_rel, other_id, write_back_func, delete_func, update_func, use_last_frame, use_num, in_use, read_only, " + "check_hash, vk_mem_size, " + "vk_mem_alignment, vk_mem_memoryTypeBits, vk_mem_property, vk_mem_memory, vk_mem_offset, vk_mem_type, vk_mem_unique_id) " + "values(:dump_id, :id, :vaddr, :vaddr2, :vaddr3, :size, :size2, :size3, :obj, :param0, :param1, :param2, :param3, :param4, " + ":param5, " + ":param6, :param7, :type, :hash, " + ":hash2, :hash3, :other_rel, :other_id, :write_back_func, :delete_func, :update_func, :use_last_frame, :use_num, :in_use, " + ":read_only, :check_hash, " + ":vk_mem_size, :vk_mem_alignment, :vk_mem_memoryTypeBits, :vk_mem_property, :vk_mem_memory, :vk_mem_offset, :vk_mem_type, " + ":vk_mem_unique_id)"); + } +} + +void GpuMemory::DbgDbDump() +{ + KYTY_PROFILER_FUNCTION(); + + Core::LockGuard lock(m_mutex); + + static int dump_id = 0; + + auto hex = [](auto u) + { + auto u64 = reinterpret_cast(u); + return (u64 == 0 ? U"0" : String::FromPrintf("0x%010" PRIx64, u64)); + }; + + auto id = [](int id1, int id2) { return id1 * 1000000 + id2; }; + + if (!m_db.IsInvalid()) + { + m_db.Exec("BEGIN TRANSACTION"); + + for (const auto& r: m_allocated) + { + m_db_add_range->Reset(); + m_db_add_range->BindInt(":dump_id", dump_id); + m_db_add_range->BindString(":vaddr", hex(r.vaddr)); + m_db_add_range->BindString(":size", hex(r.size)); + m_db_add_range->Step(); + } + + int index = 0; + for (const auto& r: m_objects) + { + if (!r.free) + { + m_db_add_object->Reset(); + m_db_add_object->BindInt(":dump_id", dump_id); + m_db_add_object->BindInt(":id", id(dump_id, index)); + (r.block.vaddr_num > 0 ? m_db_add_object->BindString(":vaddr", hex(r.block.vaddr[0])) + : m_db_add_object->BindNull(":vaddr")); + (r.block.vaddr_num > 1 ? m_db_add_object->BindString(":vaddr2", hex(r.block.vaddr[1])) + : m_db_add_object->BindNull(":vaddr2")); + (r.block.vaddr_num > 2 ? m_db_add_object->BindString(":vaddr3", hex(r.block.vaddr[2])) + : m_db_add_object->BindNull(":vaddr3")); + (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)); + 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()); + int hash0_index = m_db_add_object->GetIndex(":hash"); + for (int i = 0; i < VADDR_BLOCKS_MAX; i++) + { + m_db_add_object->BindString(hash0_index + i, hex(r.info.hash[i])); + } + m_db_add_object->BindString(":write_back_func", hex(r.info.write_back_func)); + m_db_add_object->BindString(":delete_func", hex(r.info.delete_func)); + m_db_add_object->BindString(":update_func", hex(r.info.update_func)); + m_db_add_object->BindInt64(":use_last_frame", static_cast(r.info.use_last_frame)); + m_db_add_object->BindInt64(":use_num", static_cast(r.info.use_num)); + m_db_add_object->BindInt(":in_use", static_cast(r.info.in_use)); + m_db_add_object->BindInt(":read_only", static_cast(r.info.read_only)); + m_db_add_object->BindInt(":check_hash", static_cast(r.info.check_hash)); + m_db_add_object->BindString(":vk_mem_size", hex(r.info.mem.requirements.size)); + m_db_add_object->BindString(":vk_mem_alignment", hex(r.info.mem.requirements.alignment)); + m_db_add_object->BindInt(":vk_mem_memoryTypeBits", static_cast(r.info.mem.requirements.memoryTypeBits)); + m_db_add_object->BindInt(":vk_mem_property", static_cast(r.info.mem.property)); + m_db_add_object->BindString(":vk_mem_memory", hex(r.info.mem.memory)); + m_db_add_object->BindInt64(":vk_mem_offset", static_cast(r.info.mem.offset)); + m_db_add_object->BindInt(":vk_mem_type", static_cast(r.info.mem.type)); + m_db_add_object->BindInt64(":vk_mem_unique_id", static_cast(r.info.mem.unique_id)); + + if (r.others.Size() > 0) + { + m_db_add_object->BindString(":other_rel", Core::EnumName(r.others.At(0).relation)); + m_db_add_object->BindInt(":other_id", id(dump_id, r.others.At(0).object_id)); + } else + { + m_db_add_object->BindNull(":other_rel"); + m_db_add_object->BindNull(":other_id"); + } + + m_db_add_object->Step(); + } + index++; + } + + m_db.Exec("END TRANSACTION"); + } + + dump_id++; +} + +void GpuMemory::DbgDbSave(const String& file_name) +{ + KYTY_PROFILER_FUNCTION(); + + Core::LockGuard lock(m_mutex); + + if (!m_db.IsInvalid()) + { + Core::Database::Connection db; + if (!db.Create(file_name) && !db.Open(file_name, Core::Database::Connection::Mode::ReadWrite)) + { + printf("Can't open file: %s\n", file_name.C_Str()); + return; + } + m_db.CopyTo(&db); + db.Close(); + } +} + +void GpuMemory::DbgDump() +{ + Core::LockGuard lock(m_mutex); + + printf("--- Gpu Memory ---\n"); + + for (auto& o: m_allocated) + { + printf("Allocated block: vaddr = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", o.vaddr, o.size); + } + + printf("m_current_frame = %" PRIu64 "\n", m_current_frame); + printf("m_objects_size = %" PRIu64 "\n", m_objects_size); + + for (auto& h: m_objects) + { + if (!h.free) + { + auto& block = h.block; + // EXIT_IF(block.free); + + printf("Object:\n"); + for (int vi = 0; vi < block.vaddr_num; vi++) + { + printf("\t vaddr = 0x%016" PRIx64 "\n", block.vaddr[vi]); + printf("\t size = 0x%016" PRIx64 "\n", block.size[vi]); + GpuResources::Info res_info; + if (g_gpu_resources->FindInfo(block.vaddr[vi], &res_info)) + { + printf("\t {\n"); + printf("\t\t RegisteredResource: %s\n", res_info.name.C_Str()); + printf("\t\t addr: %016" PRIx64 "\n", res_info.memory); + printf("\t\t size: %" PRIu64 "\n", res_info.size); + printf("\t\t type: %" PRIu32 "\n", res_info.type); + printf("\t\t user_data: %" PRIu64 "\n", res_info.user_data); + printf("\t }\n"); + } + } + auto& o = h.info; + printf("\t type = %s\n", Core::EnumName(o.type).C_Str()); + for (int vi = 0; vi < block.vaddr_num; vi++) + { + printf("\t hash = 0x%016" PRIx64 "\n", o.hash[vi]); + } + printf("\t vk_size = 0x%016" PRIx64 "\n", o.mem.requirements.size); + printf("\t vk_align = 0x%016" PRIx64 "\n", o.mem.requirements.alignment); + printf("\t vk_type = 0x%08" PRIx32 "\n", o.mem.type); + printf("\t use_last_frame = %" PRIu64 "\n", o.use_last_frame); + printf("\t use_num = %" PRIu64 "\n", o.use_num); + printf("\t in_use = %s\n", o.in_use ? "true" : "false"); + printf("\t read_only = %s\n", o.read_only ? "true" : "false"); + printf("\t check_hash = %s\n", o.check_hash ? "true" : "false"); + } + } +} + +void GpuMemoryInit() +{ + EXIT_IF(g_gpu_memory != nullptr); + EXIT_IF(g_gpu_resources != nullptr); + + g_gpu_memory = new GpuMemory; + g_gpu_resources = new GpuResources; +} + +void GpuMemorySetAllocatedRange(uint64_t vaddr, uint64_t size) +{ + EXIT_IF(g_gpu_memory == nullptr); + + g_gpu_memory->SetAllocatedRange(vaddr, size); +} + +void GpuMemoryFree(GraphicContext* ctx, uint64_t vaddr, uint64_t size) +{ + EXIT_IF(g_gpu_memory == nullptr); + EXIT_IF(ctx == nullptr); + + g_gpu_memory->Free(ctx, vaddr, size); +} + +void* GpuMemoryCreateObject(GraphicContext* ctx, uint64_t vaddr, uint64_t size, const GpuObject& info) +{ + EXIT_IF(g_gpu_memory == nullptr); + EXIT_IF(ctx == nullptr); + + return g_gpu_memory->CreateObject(ctx, &vaddr, &size, 1, info); +} + +void* GpuMemoryCreateObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info) +{ + EXIT_IF(g_gpu_memory == nullptr); + EXIT_IF(ctx == nullptr); + + return g_gpu_memory->CreateObject(ctx, vaddr, size, vaddr_num, info); +} + +Vector GpuMemoryFindObjects(uint64_t vaddr, uint64_t size) +{ + EXIT_IF(g_gpu_memory == nullptr); + + return g_gpu_memory->FindObjects(&vaddr, &size, 1); +} + +void GpuMemoryResetHash(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, GpuMemoryObjectType type) +{ + EXIT_IF(g_gpu_memory == nullptr); + EXIT_IF(ctx == nullptr); + + g_gpu_memory->ResetHash(ctx, vaddr, size, vaddr_num, type); +} + +void GpuMemoryDbgDump() +{ + EXIT_IF(g_gpu_memory == nullptr); + + // g_gpu_memory->DbgDbDump(); + // g_gpu_memory->DbgDump(); + // g_gpu_memory->DbgDbSave(U"_gpu_memory.db"); +} + +void GpuMemoryFlush(GraphicContext* ctx) +{ + EXIT_IF(g_gpu_memory == nullptr); + EXIT_IF(ctx == nullptr); + + // update vulkan objects after CPU-drawing + g_gpu_memory->Flush(ctx); +} + +void GpuMemoryFrameDone() +{ + EXIT_IF(g_gpu_memory == nullptr); + + g_gpu_memory->FrameDone(); +} + +void GpuMemoryWriteBack(GraphicContext* ctx) +{ + EXIT_IF(g_gpu_memory == nullptr); + EXIT_IF(ctx == nullptr); + + // update CPU memory after GPU-drawing + g_gpu_memory->WriteBack(ctx); +} + +bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* mem) +{ + static std::atomic seq = 0; + + EXIT_IF(ctx == nullptr); + EXIT_IF(mem == nullptr); + EXIT_IF(mem->memory != nullptr); + EXIT_IF(mem->requirements.size == 0); + + VkPhysicalDeviceMemoryProperties memory_properties {}; + vkGetPhysicalDeviceMemoryProperties(ctx->physical_device, &memory_properties); + + uint32_t index = 0; + for (; index < memory_properties.memoryTypeCount; index++) + { + if ((mem->requirements.memoryTypeBits & (static_cast(1) << index)) != 0 && + (memory_properties.memoryTypes[index].propertyFlags & mem->property) == mem->property) + { + break; + } + } + + mem->type = index; + mem->offset = 0; + + VkMemoryAllocateInfo alloc_info {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = nullptr; + alloc_info.allocationSize = mem->requirements.size; + alloc_info.memoryTypeIndex = index; + + mem->unique_id = ++seq; + + return (vkAllocateMemory(ctx->device, &alloc_info, nullptr, &mem->memory) == VK_SUCCESS); +} + +void VulkanFree(GraphicContext* ctx, VulkanMemory* mem) +{ + EXIT_IF(ctx == nullptr); + EXIT_IF(mem == nullptr); + + vkFreeMemory(ctx->device, mem->memory, nullptr); + + mem->memory = nullptr; +} + +void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* mem, void** data) +{ + EXIT_IF(ctx == nullptr); + EXIT_IF(mem == nullptr); + EXIT_IF(data == nullptr); + + vkMapMemory(ctx->device, mem->memory, mem->offset, mem->requirements.size, 0, data); +} + +void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* mem) +{ + EXIT_IF(ctx == nullptr); + EXIT_IF(mem == nullptr); + + vkUnmapMemory(ctx->device, mem->memory); +} + +void VulkanBindImageMemory(GraphicContext* ctx, VulkanImage* image, VulkanMemory* mem) +{ + EXIT_IF(ctx == nullptr); + EXIT_IF(mem == nullptr); + EXIT_IF(image == nullptr); + + vkBindImageMemory(ctx->device, image->image, mem->memory, mem->offset); +} + +void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* mem) +{ + EXIT_IF(ctx == nullptr); + EXIT_IF(mem == nullptr); + EXIT_IF(buffer == nullptr); + + vkBindBufferMemory(ctx->device, buffer->buffer, mem->memory, mem->offset); +} + +void GpuMemoryRegisterOwner(uint32_t* owner_handle, const char* name) +{ + EXIT_IF(g_gpu_resources == nullptr); + EXIT_IF(owner_handle == nullptr); + EXIT_IF(name == nullptr); + + *owner_handle = g_gpu_resources->AddOwner(String::FromUtf8(name)); +} + +void GpuMemoryRegisterResource(uint32_t* resource_handle, uint32_t owner_handle, const void* memory, size_t size, const char* name, + uint32_t type, uint64_t user_data) +{ + EXIT_IF(g_gpu_resources == nullptr); + EXIT_IF(resource_handle == nullptr); + EXIT_IF(name == nullptr); + + *resource_handle = + g_gpu_resources->AddResource(owner_handle, reinterpret_cast(memory), size, String::FromUtf8(name), type, user_data); +} + +void GpuMemoryUnregisterAllResourcesForOwner(uint32_t owner_handle) +{ + EXIT_IF(g_gpu_resources == nullptr); + + g_gpu_resources->DeleteResources(owner_handle); +} + +void GpuMemoryUnregisterOwnerAndResources(uint32_t owner_handle) +{ + EXIT_IF(g_gpu_resources == nullptr); + + g_gpu_resources->DeleteOwner(owner_handle); +} + +void GpuMemoryUnregisterResource(uint32_t resource_handle) +{ + EXIT_IF(g_gpu_resources == nullptr); + + g_gpu_resources->DeleteResource(resource_handle); +} + +} // namespace Kyty::Libs::Graphics + +#endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Graphics/IndexBuffer.cpp b/source/emulator/src/Graphics/Objects/IndexBuffer.cpp similarity index 98% rename from source/emulator/src/Graphics/IndexBuffer.cpp rename to source/emulator/src/Graphics/Objects/IndexBuffer.cpp index 6ed1c27..dab0f14 100644 --- a/source/emulator/src/Graphics/IndexBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/IndexBuffer.cpp @@ -1,4 +1,4 @@ -#include "Emulator/Graphics/IndexBuffer.h" +#include "Emulator/Graphics/Objects/IndexBuffer.h" #include "Kyty/Core/DbgAssert.h" diff --git a/source/emulator/src/Graphics/Label.cpp b/source/emulator/src/Graphics/Objects/Label.cpp similarity index 99% rename from source/emulator/src/Graphics/Label.cpp rename to source/emulator/src/Graphics/Objects/Label.cpp index 3986eac..0d8b448 100644 --- a/source/emulator/src/Graphics/Label.cpp +++ b/source/emulator/src/Graphics/Objects/Label.cpp @@ -1,4 +1,4 @@ -#include "Emulator/Graphics/Label.h" +#include "Emulator/Graphics/Objects/Label.h" #include "Kyty/Core/DbgAssert.h" #include "Kyty/Core/Threads.h" diff --git a/source/emulator/src/Graphics/Objects/RenderTexture.cpp b/source/emulator/src/Graphics/Objects/RenderTexture.cpp new file mode 100644 index 0000000..2b3a7b5 --- /dev/null +++ b/source/emulator/src/Graphics/Objects/RenderTexture.cpp @@ -0,0 +1,211 @@ +#include "Emulator/Graphics/Objects/RenderTexture.h" + +#include "Kyty/Core/DbgAssert.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 { + +void* RenderTextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const +{ + KYTY_PROFILER_BLOCK("RenderTextureObject::Create"); + + EXIT_IF(vaddr_num != 1 || size == nullptr || vaddr == nullptr); + EXIT_IF(mem == nullptr); + EXIT_IF(ctx == nullptr); + + auto pixel_format = params[PARAM_FORMAT]; + auto width = params[PARAM_WIDTH]; + auto height = params[PARAM_HEIGHT]; + + VkFormat vk_format = VK_FORMAT_UNDEFINED; + + switch (pixel_format) // NOLINT + { + case static_cast(RenderTextureFormat::R8G8B8A8Unorm): vk_format = VK_FORMAT_R8G8B8A8_UNORM; break; + default: EXIT("unknown format: %" PRIu64 "\n", pixel_format); + } + + EXIT_NOT_IMPLEMENTED(width == 0); + EXIT_NOT_IMPLEMENTED(height == 0); + + auto* vk_obj = new RenderTextureVulkanImage; + + vk_obj->extent.width = width; + vk_obj->extent.height = height; + vk_obj->format = vk_format; + vk_obj->image = nullptr; + vk_obj->image_view = nullptr; + + VkImageCreateInfo image_info {}; + image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_info.pNext = nullptr; + image_info.flags = 0; + image_info.imageType = VK_IMAGE_TYPE_2D; + image_info.extent.width = vk_obj->extent.width; + image_info.extent.height = vk_obj->extent.height; + image_info.extent.depth = 1; + image_info.mipLevels = 1; + image_info.arrayLayers = 1; + image_info.format = vk_obj->format; + image_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_info.usage = static_cast(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) | + static_cast(VK_IMAGE_USAGE_TRANSFER_SRC_BIT) | + static_cast(VK_IMAGE_USAGE_TRANSFER_DST_BIT) | + static_cast(VK_IMAGE_USAGE_SAMPLED_BIT); + image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_info.samples = VK_SAMPLE_COUNT_1_BIT; + + vkCreateImage(ctx->device, &image_info, nullptr, &vk_obj->image); + + EXIT_NOT_IMPLEMENTED(vk_obj->image == nullptr); + + vkGetImageMemoryRequirements(ctx->device, vk_obj->image, &mem->requirements); + + mem->property = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + bool allocated = VulkanAllocate(ctx, mem); + + EXIT_NOT_IMPLEMENTED(!allocated); + + VulkanBindImageMemory(ctx, vk_obj, mem); + + vk_obj->memory = *mem; + + printf("RenderTextureObject::Create()\n"); + printf("\t mem->requirements.size = %" PRIu64 "\n", mem->requirements.size); + printf("\t width = %" PRIu64 "\n", width); + printf("\t height = %" PRIu64 "\n", height); + printf("\t size = %" PRIu64 "\n", *size); + + // EXIT_NOT_IMPLEMENTED(mem->requirements.size > *size); + + GetUpdateFunc()(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.r = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + create_info.subresourceRange.baseArrayLayer = 0; + create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.layerCount = 1; + create_info.subresourceRange.levelCount = 1; + + vkCreateImageView(ctx->device, &create_info, nullptr, &vk_obj->image_view); + + EXIT_NOT_IMPLEMENTED(vk_obj->image_view == nullptr); + + return vk_obj; +} + +static 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"); + + auto* vk_obj = reinterpret_cast(obj); + + EXIT_IF(vk_obj == nullptr); + EXIT_IF(ctx == nullptr); + + DeleteDescriptor(vk_obj); + + DeleteFramebuffer(vk_obj); + + vkDestroyImageView(ctx->device, vk_obj->image_view, nullptr); + + vkDestroyImage(ctx->device, vk_obj->image, nullptr); + + VulkanFree(ctx, mem); + + delete vk_obj; +} + +GpuObject::delete_func_t RenderTextureObject::GetDeleteFunc() const +{ + return delete_func; +} + +GpuObject::update_func_t RenderTextureObject::GetUpdateFunc() const +{ + return update_func; +} + +} // namespace Kyty::Libs::Graphics + +#endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Graphics/StorageBuffer.cpp b/source/emulator/src/Graphics/Objects/StorageBuffer.cpp similarity index 98% rename from source/emulator/src/Graphics/StorageBuffer.cpp rename to source/emulator/src/Graphics/Objects/StorageBuffer.cpp index 61b3850..e59b319 100644 --- a/source/emulator/src/Graphics/StorageBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/StorageBuffer.cpp @@ -1,4 +1,4 @@ -#include "Emulator/Graphics/StorageBuffer.h" +#include "Emulator/Graphics/Objects/StorageBuffer.h" #include "Kyty/Core/DbgAssert.h" diff --git a/source/emulator/src/Graphics/Texture.cpp b/source/emulator/src/Graphics/Objects/Texture.cpp similarity index 97% rename from source/emulator/src/Graphics/Texture.cpp rename to source/emulator/src/Graphics/Objects/Texture.cpp index 9e60ac4..227cf03 100644 --- a/source/emulator/src/Graphics/Texture.cpp +++ b/source/emulator/src/Graphics/Objects/Texture.cpp @@ -1,4 +1,4 @@ -#include "Emulator/Graphics/Texture.h" +#include "Emulator/Graphics/Objects/Texture.h" #include "Kyty/Core/DbgAssert.h" #include "Kyty/Core/Vector.h" @@ -176,6 +176,7 @@ void* TextureObject::Create(GraphicContext* ctx, const uint64_t* vaddr, const ui 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); @@ -227,7 +228,7 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, auto* vk_obj = static_cast(obj); - bool tile = (params[TextureObject::PARAM_TILE] != 0); + 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; @@ -248,6 +249,8 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, 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); @@ -285,14 +288,14 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, } } - if (tile) + 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 + } else if (tile == 8) { UtilFillImage(ctx, vk_obj, reinterpret_cast(*vaddr), *size, regions, static_cast(vk_layout)); } diff --git a/source/emulator/src/Graphics/VertexBuffer.cpp b/source/emulator/src/Graphics/Objects/VertexBuffer.cpp similarity index 98% rename from source/emulator/src/Graphics/VertexBuffer.cpp rename to source/emulator/src/Graphics/Objects/VertexBuffer.cpp index 14a8a68..5c7b6d8 100644 --- a/source/emulator/src/Graphics/VertexBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/VertexBuffer.cpp @@ -1,4 +1,4 @@ -#include "Emulator/Graphics/VertexBuffer.h" +#include "Emulator/Graphics/Objects/VertexBuffer.h" #include "Kyty/Core/DbgAssert.h" diff --git a/source/emulator/src/Graphics/VideoOutBuffer.cpp b/source/emulator/src/Graphics/Objects/VideoOutBuffer.cpp similarity index 95% rename from source/emulator/src/Graphics/VideoOutBuffer.cpp rename to source/emulator/src/Graphics/Objects/VideoOutBuffer.cpp index 8665463..1ef95ea 100644 --- a/source/emulator/src/Graphics/VideoOutBuffer.cpp +++ b/source/emulator/src/Graphics/Objects/VideoOutBuffer.cpp @@ -1,4 +1,4 @@ -#include "Emulator/Graphics/VideoOutBuffer.h" +#include "Emulator/Graphics/Objects/VideoOutBuffer.h" #include "Kyty/Core/DbgAssert.h" @@ -37,6 +37,7 @@ void* VideoOutBufferObject::Create(GraphicContext* ctx, const uint64_t* vaddr, c vk_obj->format = VK_FORMAT_B8G8R8A8_SRGB; vk_obj->image = nullptr; vk_obj->image_view = nullptr; + vk_obj->layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageCreateInfo image_info {}; image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -50,7 +51,7 @@ void* VideoOutBufferObject::Create(GraphicContext* ctx, const uint64_t* vaddr, c image_info.arrayLayers = 1; image_info.format = vk_obj->format; image_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_info.initialLayout = vk_obj->layout; image_info.usage = static_cast(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) | VK_IMAGE_USAGE_TRANSFER_DST_BIT; image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -141,6 +142,8 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj, 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); @@ -158,7 +161,7 @@ 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_PITCH] == other[PARAM_PITCH] && params[PARAM_NEO] == other[PARAM_NEO]); } static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem) diff --git a/source/emulator/src/Graphics/Shader.cpp b/source/emulator/src/Graphics/Shader.cpp index e339d14..3567fba 100644 --- a/source/emulator/src/Graphics/Shader.cpp +++ b/source/emulator/src/Graphics/Shader.cpp @@ -3012,7 +3012,7 @@ ShaderCode ShaderParsePS(const PixelShaderInfo* regs) ps_print("ShaderParsePS()", regs->ps_regs); ps_check(regs->ps_regs); - EXIT_NOT_IMPLEMENTED(regs->ps_regs.user_sgpr != regs->ps_user_sgpr.count); + EXIT_NOT_IMPLEMENTED(regs->ps_regs.user_sgpr > regs->ps_user_sgpr.count); const auto* header = GetBinaryInfo(src); diff --git a/source/emulator/src/Graphics/Tile.cpp b/source/emulator/src/Graphics/Tile.cpp index 0e07dba..cfba05e 100644 --- a/source/emulator/src/Graphics/Tile.cpp +++ b/source/emulator/src/Graphics/Tile.cpp @@ -423,7 +423,7 @@ void TileConvertTiledToLinear(void* dst, const void* src, TileMode mode, uint32_ uint32_t padded_height[16] = {0}; uint32_t level_sizes[16] = {0}; - TileGetTextureSize(dfmt, nfmt, width, height, width, levels, true, neo, nullptr, level_sizes, padded_width, padded_height); + TileGetTextureSize(dfmt, nfmt, width, height, width, levels, 13, neo, nullptr, level_sizes, padded_width, padded_height); uint32_t mip_width = width; uint32_t mip_height = height; @@ -611,8 +611,8 @@ void TileGetVideoOutSize(uint32_t width, uint32_t height, bool tile, bool neo, u *pitch = ret_pitch; } -void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, bool tile, bool neo, - uint32_t* total_size, uint32_t* level_sizes, uint32_t* padded_width, uint32_t* padded_height) +void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile, + bool neo, uint32_t* total_size, uint32_t* level_sizes, uint32_t* padded_width, uint32_t* padded_height) { struct Padded { @@ -627,7 +627,7 @@ void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t h uint32_t width; uint32_t height; uint32_t levels; - bool tile; + uint32_t tile; bool neo; uint32_t size[16]; Padded padded[16]; @@ -635,22 +635,28 @@ void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t h static const TextureInfo infos[] = { // clang-format off - { 10, 9, 512, 512, 10, false, false, {1048576, 262144, 65536, 16384, 4096, 1024, 512, 256, 256, 256, }, + + { 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, false, true, {1048576, 262144, 65536, 16384, 4096, 1024, 512, 256, 256, 256, }, + { 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}, } }, - { 10, 9, 512, 512, 10, true, false, {1048576, 262144, 65536, 16384, 4096, 1024, 256, 256, 256, 256, }, + { 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, true, true, {1048576, 262144, 65536, 16384, 4096, 1024, 256, 256, 256, 256, }, + { 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}, } }, - { 37, 9, 512, 512, 10, false, false, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + { 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, false, true, {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}, } }, - { 37, 9, 512, 512, 10, true, false, {262144, 65536, 16384, 4096, 1024, 1024, 1024, 1024, 1024, 1024, }, + { 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, true, true, {262144, 65536, 16384, 4096, 1024, 1024, 1024, 1024, 1024, 1024, }, + { 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}, } }, + + { 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 }; @@ -684,7 +690,7 @@ void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t h } } - if (!tile && levels == 1 && dfmt == 10 && nfmt == 9) + if (tile == 8 && levels == 1 && dfmt == 10 && nfmt == 9) { uint32_t size = pitch * height * 4; if (total_size != nullptr) diff --git a/source/emulator/src/Graphics/Utils.cpp b/source/emulator/src/Graphics/Utils.cpp index bd66e6a..ff25f7e 100644 --- a/source/emulator/src/Graphics/Utils.cpp +++ b/source/emulator/src/Graphics/Utils.cpp @@ -3,9 +3,9 @@ #include "Kyty/Core/DbgAssert.h" #include "Kyty/Core/Vector.h" -#include "Emulator/Graphics/GpuMemory.h" #include "Emulator/Graphics/GraphicContext.h" #include "Emulator/Graphics/GraphicsRender.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #include "Emulator/Profiler.h" #include "vulkan/vulkan_core.h" @@ -14,11 +14,13 @@ namespace Kyty::Libs::Graphics { -static void set_image_layout(VkCommandBuffer buffer, VkImage image, uint32_t levels, VkImageAspectFlags aspect_mask, +static void set_image_layout(VkCommandBuffer buffer, VulkanImage* dst_image, uint32_t levels, VkImageAspectFlags aspect_mask, VkImageLayout old_image_layout, VkImageLayout new_image_layout) { EXIT_IF(buffer == nullptr); + EXIT_IF(dst_image->layout != old_image_layout); + VkImageMemoryBarrier image_memory_barrier {}; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = nullptr; @@ -28,7 +30,7 @@ static void set_image_layout(VkCommandBuffer buffer, VkImage image, uint32_t lev image_memory_barrier.newLayout = new_image_layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.image = image; + image_memory_barrier.image = dst_image->image; image_memory_barrier.subresourceRange.aspectMask = aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = levels; @@ -80,9 +82,11 @@ static void set_image_layout(VkCommandBuffer buffer, VkImage image, uint32_t lev VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; vkCmdPipelineBarrier(buffer, src_stages, dest_stages, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + + dst_image->layout = new_image_layout; } -void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, uint32_t src_pitch, VideoOutVulkanImage* dst_image) +void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, uint32_t src_pitch, VulkanImage* dst_image) { EXIT_IF(src_buffer == nullptr); EXIT_IF(src_buffer->buffer == nullptr); @@ -91,8 +95,7 @@ void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, uint32_t auto* vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; - set_image_layout(vk_buffer, dst_image->image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + set_image_layout(vk_buffer, dst_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkBufferImageCopy region {}; region.bufferOffset = 0; @@ -109,7 +112,7 @@ 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->image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + set_image_layout(vk_buffer, dst_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } @@ -142,16 +145,16 @@ void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, TextureV index++; } - set_image_layout(vk_buffer, dst_image->image, index, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + set_image_layout(vk_buffer, dst_image, index, 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->image, index, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 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)); } -void UtilBlitImage(CommandBuffer* buffer, VideoOutVulkanImage* src_image, VulkanSwapchain* dst_swapchain) +void UtilBlitImage(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchain* dst_swapchain) { EXIT_IF(src_image == nullptr); EXIT_IF(src_image->image == nullptr); @@ -159,11 +162,14 @@ void UtilBlitImage(CommandBuffer* buffer, VideoOutVulkanImage* src_image, Vulkan auto* vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; - auto* blt_dst_image = dst_swapchain->swapchain_images[dst_swapchain->current_index]; + VulkanImage swapchain_image {}; - set_image_layout(vk_buffer, src_image->image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + 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, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - set_image_layout(vk_buffer, blt_dst_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + set_image_layout(vk_buffer, &swapchain_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkImageBlit region {}; @@ -188,10 +194,10 @@ void UtilBlitImage(CommandBuffer* buffer, VideoOutVulkanImage* src_image, Vulkan region.dstOffsets[1].y = static_cast(dst_swapchain->swapchain_extent.height); region.dstOffsets[1].z = 1; - vkCmdBlitImage(vk_buffer, src_image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, blt_dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ®ion, VK_FILTER_LINEAR); + 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->image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + set_image_layout(vk_buffer, src_image, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } @@ -231,7 +237,7 @@ void VulkanDeleteBuffer(GraphicContext* gctx, VulkanBuffer* buffer) buffer->buffer = nullptr; } -void UtilFillImage(GraphicContext* ctx, VideoOutVulkanImage* image, const void* src_data, uint64_t size, uint32_t src_pitch) +void UtilFillImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size, uint32_t src_pitch) { KYTY_PROFILER_FUNCTION(); @@ -262,7 +268,7 @@ void UtilFillImage(GraphicContext* ctx, VideoOutVulkanImage* image, const void* VulkanDeleteBuffer(ctx, &staging_buffer); } -void UtilSetImageLayoutOptimal(DepthStencilVulkanImage* image) +void UtilSetDepthLayoutOptimal(DepthStencilVulkanImage* image) { CommandBuffer buffer; buffer.SetQueue(GraphicContext::QUEUE_UTIL); @@ -280,14 +286,14 @@ void UtilSetImageLayoutOptimal(DepthStencilVulkanImage* image) aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; } - set_image_layout(vk_buffer, image->image, 1, aspect_mask, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + set_image_layout(vk_buffer, image, 1, aspect_mask, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); buffer.End(); buffer.Execute(); buffer.WaitForFence(); } -void UtilSetImageLayoutOptimal(VideoOutVulkanImage* image) +void UtilSetImageLayoutOptimal(VulkanImage* image) { CommandBuffer buffer; buffer.SetQueue(GraphicContext::QUEUE_UTIL); @@ -300,7 +306,7 @@ void UtilSetImageLayoutOptimal(VideoOutVulkanImage* image) VkImageAspectFlags aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; - set_image_layout(vk_buffer, image->image, 1, aspect_mask, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + set_image_layout(vk_buffer, image, 1, aspect_mask, image->layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); buffer.End(); buffer.Execute(); diff --git a/source/emulator/src/Graphics/VideoOut.cpp b/source/emulator/src/Graphics/VideoOut.cpp index 0a83755..e0d0f63 100644 --- a/source/emulator/src/Graphics/VideoOut.cpp +++ b/source/emulator/src/Graphics/VideoOut.cpp @@ -9,10 +9,10 @@ #include "Emulator/Common.h" #include "Emulator/Config.h" -#include "Emulator/Graphics/GpuMemory.h" #include "Emulator/Graphics/GraphicsRender.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" +#include "Emulator/Graphics/Objects/VideoOutBuffer.h" #include "Emulator/Graphics/Tile.h" -#include "Emulator/Graphics/VideoOutBuffer.h" #include "Emulator/Graphics/Window.h" #include "Emulator/Kernel/Pthread.h" #include "Emulator/Libs/Errno.h" @@ -845,7 +845,7 @@ KYTY_SYSV_ABI int VideoOutRegisterBuffers(int handle, int start_index, void* con ctx->buffers[i + start_index].buffer = addresses[i]; ctx->buffers[i + start_index].buffer_size = buffer_size; ctx->buffers[i + start_index].buffer_pitch = buffer_pitch; - ctx->buffers[i + start_index].buffer_vulkan = static_cast(Graphics::GpuMemoryGetObject( + ctx->buffers[i + start_index].buffer_vulkan = static_cast(Graphics::GpuMemoryCreateObject( g_video_out_context->GetGraphicCtx(), reinterpret_cast(addresses[i]), buffer_size, vulkan_buffer_info)); EXIT_NOT_IMPLEMENTED(ctx->buffers[i + start_index].buffer_vulkan == nullptr); diff --git a/source/emulator/src/Kernel/Memory.cpp b/source/emulator/src/Kernel/Memory.cpp index 755d550..d10f96f 100644 --- a/source/emulator/src/Kernel/Memory.cpp +++ b/source/emulator/src/Kernel/Memory.cpp @@ -6,8 +6,8 @@ #include "Kyty/Core/Threads.h" #include "Kyty/Core/Vector.h" -#include "Emulator/Graphics/GpuMemory.h" #include "Emulator/Graphics/GraphicsRun.h" +#include "Emulator/Graphics/Objects/GpuMemory.h" #include "Emulator/Graphics/Window.h" #include "Emulator/Libs/Errno.h" #include "Emulator/Libs/Libs.h" diff --git a/source/emulator/src/Kernel/Semaphore.cpp b/source/emulator/src/Kernel/Semaphore.cpp index 9b81392..90bcd55 100644 --- a/source/emulator/src/Kernel/Semaphore.cpp +++ b/source/emulator/src/Kernel/Semaphore.cpp @@ -27,8 +27,8 @@ public: InvalCount }; - KernelSemaPrivate(const String& name, bool fifo, int init_count, int max_count) - : m_name(name), m_fifo_order(fifo), m_count(init_count), m_init_count(init_count), m_max_count(max_count) {}; + KernelSemaPrivate(const String& name, bool /*fifo*/, int init_count, int max_count) + : m_name(name), /*m_fifo_order(fifo),*/ m_count(init_count), m_init_count(init_count), m_max_count(max_count) {}; virtual ~KernelSemaPrivate(); KYTY_CLASS_NO_COPY(KernelSemaPrivate); @@ -53,15 +53,15 @@ private: Deleted }; - Core::Mutex m_mutex; - Core::CondVar m_cond_var; - String m_name; - Status m_status = Status::Set; - Vector m_waiting_threads; - [[maybe_unused]] bool m_fifo_order; - int m_count; - int m_init_count; - int m_max_count; + Core::Mutex m_mutex; + Core::CondVar m_cond_var; + String m_name; + Status m_status = Status::Set; + Vector m_waiting_threads; + // bool m_fifo_order; + int m_count; + int m_init_count; + int m_max_count; }; KernelSemaPrivate::~KernelSemaPrivate()