Implement Vulkan.

This commit is contained in:
Skyth 2024-10-07 20:50:39 +03:00
parent 51df78e5c9
commit c07b827a5e
12 changed files with 4716 additions and 50 deletions

9
.gitmodules vendored
View file

@ -14,3 +14,12 @@
[submodule "thirdparty/ddspp"] [submodule "thirdparty/ddspp"]
path = thirdparty/ddspp path = thirdparty/ddspp
url = https://github.com/redorav/ddspp.git url = https://github.com/redorav/ddspp.git
[submodule "thirdparty/Vulkan-Headers"]
path = thirdparty/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers
[submodule "thirdparty/VulkanMemoryAllocator"]
path = thirdparty/VulkanMemoryAllocator
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
[submodule "thirdparty/volk"]
path = thirdparty/volk
url = https://github.com/zeux/volk.git

View file

@ -43,6 +43,7 @@ set(SWA_GPU_CXX_SOURCES
"gpu/window.cpp" "gpu/window.cpp"
"gpu/video.cpp" "gpu/video.cpp"
"gpu/rhi/rt64_d3d12.cpp" "gpu/rhi/rt64_d3d12.cpp"
"gpu/rhi/rt64_vulkan.cpp"
) )
set(SWA_APU_CXX_SOURCES set(SWA_APU_CXX_SOURCES
@ -85,7 +86,12 @@ target_include_directories(UnleashedRecomp PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${SWA_THIRDPARTY_ROOT}/ddspp ${SWA_THIRDPARTY_ROOT}/ddspp
${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include ${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include
${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src) ${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src
${SWA_THIRDPARTY_ROOT}/volk
${SWA_THIRDPARTY_ROOT}/Vulkan-Headers/include
${SWA_THIRDPARTY_ROOT}/VulkanMemoryAllocator/include
${SWA_THIRDPARTY_ROOT}/VulkanMemoryAllocator/src
)
target_precompile_headers(UnleashedRecomp PUBLIC ${SWA_PRECOMPILED_HEADERS}) target_precompile_headers(UnleashedRecomp PUBLIC ${SWA_PRECOMPILED_HEADERS})

View file

@ -1441,10 +1441,6 @@ namespace RT64 {
} }
} }
bool D3D12CommandList::isOpen() {
return open;
}
void D3D12CommandList::begin() { void D3D12CommandList::begin() {
assert(!open); assert(!open);
@ -1622,13 +1618,18 @@ namespace RT64 {
activeComputePipelineLayout = interfacePipelineLayout; activeComputePipelineLayout = interfacePipelineLayout;
} }
void D3D12CommandList::setComputePushConstants(uint32_t rangeIndex, const void *data) { void D3D12CommandList::setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) {
assert(activeComputePipelineLayout != nullptr); assert(activeComputePipelineLayout != nullptr);
assert(rangeIndex < activeComputePipelineLayout->pushConstantRanges.size()); assert(rangeIndex < activeComputePipelineLayout->pushConstantRanges.size());
const RenderPushConstantRange &range = activeComputePipelineLayout->pushConstantRanges[rangeIndex]; const RenderPushConstantRange &range = activeComputePipelineLayout->pushConstantRanges[rangeIndex];
assert((range.offset == 0) && "Offset behavior should be verified when compared to Vulkan."); assert((range.offset == 0) && "Offset behavior should be verified when compared to Vulkan.");
d3d->SetComputeRoot32BitConstants(rangeIndex, (range.size + sizeof(uint32_t) - 1) / sizeof(uint32_t), data, 0);
if (size == 0) {
size = range.size;
}
d3d->SetComputeRoot32BitConstants(rangeIndex, (size + sizeof(uint32_t) - 1) / sizeof(uint32_t), data, (offset + sizeof(uint32_t) - 1) / sizeof(uint32_t));
} }
void D3D12CommandList::setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { void D3D12CommandList::setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) {
@ -1643,13 +1644,18 @@ namespace RT64 {
activeGraphicsPipelineLayout = interfacePipelineLayout; activeGraphicsPipelineLayout = interfacePipelineLayout;
} }
void D3D12CommandList::setGraphicsPushConstants(uint32_t rangeIndex, const void *data) { void D3D12CommandList::setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) {
assert(activeGraphicsPipelineLayout != nullptr); assert(activeGraphicsPipelineLayout != nullptr);
assert(rangeIndex < activeGraphicsPipelineLayout->pushConstantRanges.size()); assert(rangeIndex < activeGraphicsPipelineLayout->pushConstantRanges.size());
const RenderPushConstantRange &range = activeGraphicsPipelineLayout->pushConstantRanges[rangeIndex]; const RenderPushConstantRange &range = activeGraphicsPipelineLayout->pushConstantRanges[rangeIndex];
assert((range.offset == 0) && "Offset behavior should be verified when compared to Vulkan."); assert((range.offset == 0) && "Offset behavior should be verified when compared to Vulkan.");
d3d->SetGraphicsRoot32BitConstants(rangeIndex, (range.size + sizeof(uint32_t) - 1) / sizeof(uint32_t), data, 0);
if (size == 0) {
size = range.size;
}
d3d->SetGraphicsRoot32BitConstants(rangeIndex, (size + sizeof(uint32_t) - 1) / sizeof(uint32_t), data, (offset + sizeof(uint32_t) - 1) / sizeof(uint32_t));
} }
void D3D12CommandList::setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { void D3D12CommandList::setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) {
@ -1664,8 +1670,8 @@ namespace RT64 {
setComputePipelineLayout(pipelineLayout); setComputePipelineLayout(pipelineLayout);
} }
void D3D12CommandList::setRaytracingPushConstants(uint32_t rangeIndex, const void *data) { void D3D12CommandList::setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) {
setComputePushConstants(rangeIndex, data); setComputePushConstants(rangeIndex, data, offset, size);
} }
void D3D12CommandList::setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { void D3D12CommandList::setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) {
@ -2302,6 +2308,10 @@ namespace RT64 {
setObjectName(d3d, name); setObjectName(d3d, name);
} }
uint64_t D3D12Buffer::getDeviceAddress() const {
return d3d->GetGPUVirtualAddress();
}
// D3D12BufferFormattedView // D3D12BufferFormattedView
D3D12BufferFormattedView::D3D12BufferFormattedView(D3D12Buffer *buffer, RenderFormat format) { D3D12BufferFormattedView::D3D12BufferFormattedView(D3D12Buffer *buffer, RenderFormat format) {
@ -2675,7 +2685,9 @@ namespace RT64 {
psoDesc.PS.BytecodeLength = (pixelShader != nullptr) ? pixelShader->d3d.size() : 0; psoDesc.PS.BytecodeLength = (pixelShader != nullptr) ? pixelShader->d3d.size() : 0;
psoDesc.SampleMask = UINT_MAX; psoDesc.SampleMask = UINT_MAX;
psoDesc.SampleDesc.Count = desc.multisampling.sampleCount; psoDesc.SampleDesc.Count = desc.multisampling.sampleCount;
psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; if (desc.primitiveTopology == RenderPrimitiveTopology::LINE_STRIP || desc.primitiveTopology == RenderPrimitiveTopology::TRIANGLE_STRIP) {
psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
}
psoDesc.PrimitiveTopologyType = toTopologyType(desc.primitiveTopology); psoDesc.PrimitiveTopologyType = toTopologyType(desc.primitiveTopology);
psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
psoDesc.RasterizerState.DepthClipEnable = desc.depthClipEnabled; psoDesc.RasterizerState.DepthClipEnable = desc.depthClipEnabled;

View file

@ -159,7 +159,6 @@ namespace RT64 {
D3D12CommandList(D3D12Device *device, RenderCommandListType type); D3D12CommandList(D3D12Device *device, RenderCommandListType type);
~D3D12CommandList() override; ~D3D12CommandList() override;
bool isOpen() override;
void begin() override; void begin() override;
void end() override; void end() override;
void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) override; void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) override;
@ -169,14 +168,14 @@ namespace RT64 {
void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) override; void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) override;
void setPipeline(const RenderPipeline *pipeline) override; void setPipeline(const RenderPipeline *pipeline) override;
void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) override; void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) override;
void setComputePushConstants(uint32_t rangeIndex, const void *data) override; void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override;
void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override;
void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) override;
void setGraphicsPushConstants(uint32_t rangeIndex, const void *data) override; void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override;
void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override;
void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) override; void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) override;
void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) override;
void setRaytracingPushConstants(uint32_t rangeIndex, const void *data) override; void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override;
void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override;
void setIndexBuffer(const RenderIndexBufferView *view) override; void setIndexBuffer(const RenderIndexBufferView *view) override;
void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) override; void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) override;
@ -250,6 +249,7 @@ namespace RT64 {
void unmap(uint32_t subresource, const RenderRange *writtenRange) override; void unmap(uint32_t subresource, const RenderRange *writtenRange) override;
std::unique_ptr<RenderBufferFormattedView> createBufferFormattedView(RenderFormat format) override; std::unique_ptr<RenderBufferFormattedView> createBufferFormattedView(RenderFormat format) override;
void setName(const std::string &name) override; void setName(const std::string &name) override;
uint64_t getDeviceAddress() const override;
}; };
struct D3D12BufferFormattedView : RenderBufferFormattedView { struct D3D12BufferFormattedView : RenderBufferFormattedView {

View file

@ -21,6 +21,7 @@ namespace RT64 {
virtual void unmap(uint32_t subresource = 0, const RenderRange *writtenRange = nullptr) = 0; virtual void unmap(uint32_t subresource = 0, const RenderRange *writtenRange = nullptr) = 0;
virtual std::unique_ptr<RenderBufferFormattedView> createBufferFormattedView(RenderFormat format) = 0; virtual std::unique_ptr<RenderBufferFormattedView> createBufferFormattedView(RenderFormat format) = 0;
virtual void setName(const std::string &name) = 0; virtual void setName(const std::string &name) = 0;
virtual uint64_t getDeviceAddress() const = 0;
// Concrete implementation shortcuts. // Concrete implementation shortcuts.
inline RenderBufferReference at(uint64_t offset) const { inline RenderBufferReference at(uint64_t offset) const {
@ -104,7 +105,6 @@ namespace RT64 {
struct RenderCommandList { struct RenderCommandList {
virtual ~RenderCommandList() { } virtual ~RenderCommandList() { }
virtual bool isOpen() = 0;
virtual void begin() = 0; virtual void begin() = 0;
virtual void end() = 0; virtual void end() = 0;
virtual void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) = 0; virtual void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) = 0;
@ -114,14 +114,14 @@ namespace RT64 {
virtual void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) = 0; virtual void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) = 0;
virtual void setPipeline(const RenderPipeline *pipeline) = 0; virtual void setPipeline(const RenderPipeline *pipeline) = 0;
virtual void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; virtual void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0;
virtual void setComputePushConstants(uint32_t rangeIndex, const void *data) = 0; virtual void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0;
virtual void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; virtual void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0;
virtual void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; virtual void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0;
virtual void setGraphicsPushConstants(uint32_t rangeIndex, const void *data) = 0; virtual void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0;
virtual void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; virtual void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0;
virtual void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) = 0; virtual void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) = 0;
virtual void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; virtual void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0;
virtual void setRaytracingPushConstants(uint32_t rangeIndex, const void *data) = 0; virtual void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0;
virtual void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; virtual void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0;
virtual void setIndexBuffer(const RenderIndexBufferView *view) = 0; virtual void setIndexBuffer(const RenderIndexBufferView *view) = 0;
virtual void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) = 0; virtual void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) = 0;

View file

@ -405,7 +405,8 @@ namespace RT64 {
RENDER_TARGET = 1U << 0, RENDER_TARGET = 1U << 0,
DEPTH_TARGET = 1U << 1, DEPTH_TARGET = 1U << 1,
STORAGE = 1U << 2, STORAGE = 1U << 2,
UNORDERED_ACCESS = 1U << 3 UNORDERED_ACCESS = 1U << 3,
CUBE = 1U << 4
}; };
}; };

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,409 @@
//
// RT64
//
#pragma once
#include "rt64_render_interface.h"
#include <mutex>
#include <set>
#include <unordered_map>
#include <unordered_set>
#if defined(_WIN64)
#define VK_USE_PLATFORM_WIN32_KHR
#elif defined(__ANDROID__)
#define VK_USE_PLATFORM_ANDROID_KHR
#elif defined(__linux__)
#define VK_USE_PLATFORM_XLIB_KHR
#endif
#include "volk.h"
#include "vk_mem_alloc.h"
namespace RT64 {
struct VulkanCommandQueue;
struct VulkanDevice;
struct VulkanInterface;
struct VulkanPool;
struct VulkanQueue;
struct VulkanBuffer : RenderBuffer {
VkBuffer vk = VK_NULL_HANDLE;
VulkanDevice *device = nullptr;
VulkanPool *pool = nullptr;
VmaAllocation allocation = VK_NULL_HANDLE;
VmaAllocationInfo allocationInfo = {};
RenderBufferDesc desc;
RenderBarrierStages barrierStages = RenderBarrierStage::NONE;
VulkanBuffer() = default;
VulkanBuffer(VulkanDevice *device, VulkanPool *pool, const RenderBufferDesc &desc);
~VulkanBuffer() override;
void *map(uint32_t subresource, const RenderRange *readRange) override;
void unmap(uint32_t subresource, const RenderRange *writtenRange) override;
std::unique_ptr<RenderBufferFormattedView> createBufferFormattedView(RenderFormat format) override;
void setName(const std::string &name) override;
uint64_t getDeviceAddress() const override;
};
struct VulkanBufferFormattedView : RenderBufferFormattedView {
VkBufferView vk = VK_NULL_HANDLE;
VulkanBuffer *buffer = nullptr;
VulkanBufferFormattedView(VulkanBuffer *buffer, RenderFormat format);
~VulkanBufferFormattedView() override;
};
struct VulkanTexture : RenderTexture {
VkImage vk = VK_NULL_HANDLE;
VkImageView imageView = VK_NULL_HANDLE;
VkFormat imageFormat = VK_FORMAT_UNDEFINED;
VkImageSubresourceRange imageSubresourceRange = {};
VulkanDevice *device = nullptr;
VulkanPool *pool = nullptr;
VmaAllocation allocation = VK_NULL_HANDLE;
VmaAllocationInfo allocationInfo = {};
RenderTextureLayout textureLayout = RenderTextureLayout::UNKNOWN;
RenderBarrierStages barrierStages = RenderBarrierStage::NONE;
bool ownership = false;
RenderTextureDesc desc;
VulkanTexture() = default;
VulkanTexture(VulkanDevice *device, VulkanPool *pool, const RenderTextureDesc &desc);
VulkanTexture(VulkanDevice *device, VkImage image);
~VulkanTexture() override;
void createImageView(VkFormat format);
std::unique_ptr<RenderTextureView> createTextureView(const RenderTextureViewDesc &desc) override;
void setName(const std::string &name) override;
void fillSubresourceRange();
};
struct VulkanTextureView : RenderTextureView {
VkImageView vk = VK_NULL_HANDLE;
VulkanTexture *texture = nullptr;
VulkanTextureView(VulkanTexture *texture, const RenderTextureViewDesc &desc);
~VulkanTextureView() override;
};
struct VulkanAccelerationStructure : RenderAccelerationStructure {
VkAccelerationStructureKHR vk = VK_NULL_HANDLE;
VulkanDevice *device = nullptr;
RenderAccelerationStructureType type = RenderAccelerationStructureType::UNKNOWN;
VulkanAccelerationStructure(VulkanDevice *device, const RenderAccelerationStructureDesc &desc);
~VulkanAccelerationStructure() override;
};
struct VulkanDescriptorSetLayout {
VkDescriptorSetLayout vk = VK_NULL_HANDLE;
std::vector<VkDescriptorSetLayoutBinding> setBindings;
std::vector<uint32_t> descriptorIndexBases;
std::vector<uint32_t> descriptorBindingIndices;
VulkanDevice *device = nullptr;
VulkanDescriptorSetLayout(VulkanDevice *device, const RenderDescriptorSetDesc &descriptorSetDesc);
~VulkanDescriptorSetLayout();
};
struct VulkanPipelineLayout : RenderPipelineLayout {
VkPipelineLayout vk = VK_NULL_HANDLE;
std::vector<VkPushConstantRange> pushConstantRanges;
std::vector<VulkanDescriptorSetLayout *> descriptorSetLayouts;
VulkanDevice *device = nullptr;
VulkanPipelineLayout(VulkanDevice *device, const RenderPipelineLayoutDesc &desc);
~VulkanPipelineLayout() override;
};
struct VulkanShader : RenderShader {
VkShaderModule vk = VK_NULL_HANDLE;
std::string entryPointName;
VulkanDevice *device = nullptr;
RenderShaderFormat format = RenderShaderFormat::UNKNOWN;
VulkanShader(VulkanDevice *device, const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format);
~VulkanShader() override;
};
struct VulkanSampler : RenderSampler {
VkSampler vk = VK_NULL_HANDLE;
VulkanDevice *device = nullptr;
VulkanSampler(VulkanDevice *device, const RenderSamplerDesc &desc);
~VulkanSampler();
};
struct VulkanPipeline : RenderPipeline {
enum class Type {
Unknown,
Compute,
Graphics,
Raytracing
};
VulkanDevice *device = nullptr;
Type type = Type::Unknown;
VulkanPipeline(VulkanDevice *device, Type type);
virtual ~VulkanPipeline() override;
};
struct VulkanComputePipeline : VulkanPipeline {
VkPipeline vk = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VulkanComputePipeline(VulkanDevice *device, const RenderComputePipelineDesc &desc);
~VulkanComputePipeline() override;
RenderPipelineProgram getProgram(const std::string &name) const override;
};
struct VulkanGraphicsPipeline : VulkanPipeline {
VkPipeline vk = VK_NULL_HANDLE;
VkRenderPass renderPass = VK_NULL_HANDLE;
VulkanGraphicsPipeline(VulkanDevice *device, const RenderGraphicsPipelineDesc &desc);
~VulkanGraphicsPipeline() override;
RenderPipelineProgram getProgram(const std::string &name) const override;
static VkRenderPass createRenderPass(VulkanDevice *device, const VkFormat *renderTargetFormat, uint32_t renderTargetCount, VkFormat depthTargetFormat, VkSampleCountFlagBits sampleCount);
};
struct VulkanRaytracingPipeline : VulkanPipeline {
VkPipeline vk = VK_NULL_HANDLE;
std::unordered_map<std::string, RenderPipelineProgram> nameProgramMap;
uint32_t groupCount = 0;
uint32_t descriptorSetCount = 0;
VulkanRaytracingPipeline(VulkanDevice *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline);
~VulkanRaytracingPipeline() override;
RenderPipelineProgram getProgram(const std::string &name) const override;
};
struct VulkanDescriptorSet : RenderDescriptorSet {
VkDescriptorSet vk = VK_NULL_HANDLE;
VulkanDescriptorSetLayout *setLayout = nullptr;
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
VulkanDevice *device = nullptr;
VulkanDescriptorSet(VulkanDevice *device, const RenderDescriptorSetDesc &desc);
~VulkanDescriptorSet() override;
void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView *bufferStructuredView, const RenderBufferFormattedView *bufferFormattedView) override;
void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, RenderTextureLayout textureLayout, const RenderTextureView *textureView) override;
void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) override;
void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) override;
void setDescriptor(uint32_t descriptorIndex, const VkDescriptorBufferInfo *bufferInfo, const VkDescriptorImageInfo *imageInfo, const VkBufferView *texelBufferView, void *pNext);
static VkDescriptorPool createDescriptorPool(VulkanDevice *device, const std::unordered_map<VkDescriptorType, uint32_t> &typeCounts, bool lastRangeIsBoundless);
};
struct VulkanSwapChain : RenderSwapChain {
VkSwapchainKHR vk = VK_NULL_HANDLE;
VulkanCommandQueue *commandQueue = nullptr;
VkSurfaceKHR surface = VK_NULL_HANDLE;
RenderWindow renderWindow = {};
uint32_t textureCount = 0;
uint64_t presentCount = 0;
RenderFormat format = RenderFormat::UNKNOWN;
uint32_t width = 0;
uint32_t height = 0;
VkSwapchainCreateInfoKHR createInfo = {};
VkSurfaceFormatKHR pickedSurfaceFormat = {};
VkPresentModeKHR pickedPresentMode = VK_PRESENT_MODE_FIFO_KHR;
VkCompositeAlphaFlagBitsKHR pickedAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
std::vector<VulkanTexture> textures;
VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format);
~VulkanSwapChain() override;
bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override;
bool resize() override;
bool needsResize() const override;
uint32_t getWidth() const override;
uint32_t getHeight() const override;
RenderTexture *getTexture(uint32_t textureIndex) override;
uint32_t getTextureCount() const override;
bool acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) override;
RenderWindow getWindow() const override;
bool isEmpty() const override;
uint32_t getRefreshRate() const override;
void getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const;
void releaseSwapChain();
void releaseImageViews();
};
struct VulkanFramebuffer : RenderFramebuffer {
VulkanDevice *device = nullptr;
VkFramebuffer vk = VK_NULL_HANDLE;
VkRenderPass renderPass = VK_NULL_HANDLE;
std::vector<const VulkanTexture *> colorAttachments;
const VulkanTexture *depthAttachment = nullptr;
bool depthAttachmentReadOnly = false;
uint32_t width = 0;
uint32_t height = 0;
VulkanFramebuffer(VulkanDevice *device, const RenderFramebufferDesc &desc);
~VulkanFramebuffer() override;
uint32_t getWidth() const override;
uint32_t getHeight() const override;
bool contains(const VulkanTexture *attachment) const;
};
struct VulkanCommandList : RenderCommandList {
VkCommandBuffer vk = VK_NULL_HANDLE;
VkCommandPool commandPool = VK_NULL_HANDLE;
VulkanDevice *device = nullptr;
RenderCommandListType type = RenderCommandListType::UNKNOWN;
const VulkanFramebuffer *targetFramebuffer = nullptr;
const VulkanPipelineLayout *activeComputePipelineLayout = nullptr;
const VulkanPipelineLayout *activeGraphicsPipelineLayout = nullptr;
const VulkanPipelineLayout *activeRaytracingPipelineLayout = nullptr;
VkRenderPass activeRenderPass = VK_NULL_HANDLE;
VulkanCommandList(VulkanDevice *device, RenderCommandListType type);
~VulkanCommandList() override;
void begin() override;
void end() override;
void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) override;
void dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) override;
void traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) override;
void drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) override;
void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) override;
void setPipeline(const RenderPipeline *pipeline) override;
void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) override;
void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override;
void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override;
void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) override;
void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override;
void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override;
void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) override;
void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) override;
void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override;
void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override;
void setIndexBuffer(const RenderIndexBufferView *view) override;
void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) override;
void setViewports(const RenderViewport *viewports, uint32_t count) override;
void setScissors(const RenderRect *scissorRects, uint32_t count) override;
void setFramebuffer(const RenderFramebuffer *framebuffer) override;
void clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
void clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) override;
void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX, uint32_t dstY, uint32_t dstZ, const RenderBox *srcBox) override;
void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override;
void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect) override;
void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override;
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
void checkActiveRenderPass();
void endActiveRenderPass();
void setDescriptorSet(VkPipelineBindPoint bindPoint, const VulkanPipelineLayout *pipelineLayout, const RenderDescriptorSet *descriptorSet, uint32_t setIndex);
};
struct VulkanCommandFence : RenderCommandFence {
VkFence vk = VK_NULL_HANDLE;
VulkanDevice *device = nullptr;
VulkanCommandFence(VulkanDevice *device);
~VulkanCommandFence() override;
};
struct VulkanCommandSemaphore : RenderCommandSemaphore {
VkSemaphore vk = VK_NULL_HANDLE;
VulkanDevice *device = nullptr;
VulkanCommandSemaphore(VulkanDevice *device);
~VulkanCommandSemaphore() override;
};
struct VulkanCommandQueue : RenderCommandQueue {
VulkanQueue *queue = nullptr;
VulkanDevice *device = nullptr;
uint32_t familyIndex = 0;
uint32_t queueIndex = 0;
std::unordered_set<VulkanSwapChain *> swapChains;
VulkanCommandQueue(VulkanDevice *device, RenderCommandListType commandListType);
~VulkanCommandQueue() override;
std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format) override;
void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override;
void waitForCommandFence(RenderCommandFence *fence) override;
};
struct VulkanPool : RenderPool {
VmaPool vk = VK_NULL_HANDLE;
VulkanDevice *device = nullptr;
VulkanPool(VulkanDevice *device, const RenderPoolDesc &desc);
~VulkanPool() override;
std::unique_ptr<RenderBuffer> createBuffer(const RenderBufferDesc &desc) override;
std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) override;
};
struct VulkanQueue {
VkQueue vk;
std::unique_ptr<std::mutex> mutex;
std::unordered_set<const VulkanCommandQueue *> virtualQueues;
};
struct VulkanQueueFamily {
std::vector<VulkanQueue> queues;
void add(VulkanCommandQueue *virtualQueue);
void remove(VulkanCommandQueue *virtualQueue);
};
struct VulkanDevice : RenderDevice {
VkDevice vk = VK_NULL_HANDLE;
VulkanInterface *renderInterface = nullptr;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkPhysicalDeviceProperties physicalDeviceProperties = {};
VmaAllocator allocator = VK_NULL_HANDLE;
uint32_t queueFamilyIndices[3] = {};
std::vector<VulkanQueueFamily> queueFamilies;
RenderDeviceCapabilities capabilities;
RenderDeviceDescription description;
VkPhysicalDeviceRayTracingPipelinePropertiesKHR rtPipelineProperties = {};
VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationProperties = {};
bool loadStoreOpNoneSupported = false;
VulkanDevice(VulkanInterface *renderInterface);
~VulkanDevice() override;
std::unique_ptr<RenderCommandList> createCommandList(RenderCommandListType type) override;
std::unique_ptr<RenderDescriptorSet> createDescriptorSet(const RenderDescriptorSetDesc &desc) override;
std::unique_ptr<RenderShader> createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) override;
std::unique_ptr<RenderSampler> createSampler(const RenderSamplerDesc &desc) override;
std::unique_ptr<RenderPipeline> createComputePipeline(const RenderComputePipelineDesc &desc) override;
std::unique_ptr<RenderPipeline> createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) override;
std::unique_ptr<RenderPipeline> createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) override;
std::unique_ptr<RenderCommandQueue> createCommandQueue(RenderCommandListType type) override;
std::unique_ptr<RenderBuffer> createBuffer(const RenderBufferDesc &desc) override;
std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) override;
std::unique_ptr<RenderAccelerationStructure> createAccelerationStructure(const RenderAccelerationStructureDesc &desc) override;
std::unique_ptr<RenderPool> createPool(const RenderPoolDesc &desc) override;
std::unique_ptr<RenderPipelineLayout> createPipelineLayout(const RenderPipelineLayoutDesc &desc) override;
std::unique_ptr<RenderCommandFence> createCommandFence() override;
std::unique_ptr<RenderCommandSemaphore> createCommandSemaphore() override;
std::unique_ptr<RenderFramebuffer> createFramebuffer(const RenderFramebufferDesc &desc) override;
void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) override;
void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) override;
void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) override;
const RenderDeviceCapabilities &getCapabilities() const override;
const RenderDeviceDescription &getDescription() const override;
RenderSampleCounts getSampleCountsSupported(RenderFormat format) const override;
void release();
bool isValid() const;
};
struct VulkanInterface : RenderInterface {
VkInstance instance = VK_NULL_HANDLE;
VkApplicationInfo appInfo = {};
RenderInterfaceCapabilities capabilities;
VulkanInterface();
~VulkanInterface() override;
std::unique_ptr<RenderDevice> createDevice() override;
const RenderInterfaceCapabilities &getCapabilities() const override;
bool isValid() const;
};
};

View file

@ -62,7 +62,7 @@ static bool g_scissorTestEnable = false;
static RenderRect g_scissorRect; static RenderRect g_scissorRect;
static RenderVertexBufferView g_vertexBufferViews[16]; static RenderVertexBufferView g_vertexBufferViews[16];
static RenderInputSlot g_inputSlots[16]; static RenderInputSlot g_inputSlots[16];
static RenderIndexBufferView g_indexBufferView; static RenderIndexBufferView g_indexBufferView({}, 0, RenderFormat::R16_UINT);
struct DirtyStates struct DirtyStates
{ {
@ -104,6 +104,7 @@ static void SetDirtyValue(bool& dirtyState, T& dest, const T& src)
} }
} }
static bool g_vulkan = false;
static std::unique_ptr<RenderInterface> g_interface; static std::unique_ptr<RenderInterface> g_interface;
static std::unique_ptr<RenderDevice> g_device; static std::unique_ptr<RenderDevice> g_device;
@ -122,6 +123,8 @@ static std::unique_ptr<RenderCommandList> g_copyCommandList;
static std::unique_ptr<RenderCommandFence> g_copyCommandFence; static std::unique_ptr<RenderCommandFence> g_copyCommandFence;
static std::unique_ptr<RenderSwapChain> g_swapChain; static std::unique_ptr<RenderSwapChain> g_swapChain;
static std::unique_ptr<RenderCommandSemaphore> g_acquireSemaphores[NUM_FRAMES];
static uint32_t g_backBufferIndex;
static GuestSurface* g_backBuffer; static GuestSurface* g_backBuffer;
struct std::unique_ptr<RenderDescriptorSet> g_textureDescriptorSet; struct std::unique_ptr<RenderDescriptorSet> g_textureDescriptorSet;
@ -201,7 +204,7 @@ struct UploadAllocator
auto& buffer = buffers[index]; auto& buffer = buffers[index];
if (buffer.buffer == nullptr) if (buffer.buffer == nullptr)
{ {
buffer.buffer = g_device->createBuffer(RenderBufferDesc::UploadBuffer(UploadBuffer::SIZE)); buffer.buffer = g_device->createBuffer(RenderBufferDesc::UploadBuffer(UploadBuffer::SIZE, RenderBufferFlag::CONSTANT | RenderBufferFlag::VERTEX | RenderBufferFlag::INDEX));
buffer.memory = reinterpret_cast<uint8_t*>(buffer.buffer->map()); buffer.memory = reinterpret_cast<uint8_t*>(buffer.buffer->map());
} }
@ -472,7 +475,7 @@ static void CreateHostDevice()
Window::Init(); Window::Init();
g_interface = CreateD3D12Interface(); g_interface = g_vulkan ? CreateVulkanInterface() : CreateD3D12Interface();
g_device = g_interface->createDevice(); g_device = g_interface->createDevice();
g_queue = g_device->createCommandQueue(RenderCommandListType::DIRECT); g_queue = g_device->createCommandQueue(RenderCommandListType::DIRECT);
@ -488,6 +491,13 @@ static void CreateHostDevice()
g_copyCommandFence = g_device->createCommandFence(); g_copyCommandFence = g_device->createCommandFence();
g_swapChain = g_queue->createSwapChain(Window::s_windowHandle, 2, RenderFormat::R8G8B8A8_UNORM); g_swapChain = g_queue->createSwapChain(Window::s_windowHandle, 2, RenderFormat::R8G8B8A8_UNORM);
g_swapChain->resize();
if (g_vulkan)
{
for (auto& acquireSemaphore : g_acquireSemaphores)
acquireSemaphore = g_device->createCommandSemaphore();
}
RenderPipelineLayoutBuilder pipelineLayoutBuilder; RenderPipelineLayoutBuilder pipelineLayoutBuilder;
pipelineLayoutBuilder.begin(false, true); pipelineLayoutBuilder.begin(false, true);
@ -512,9 +522,16 @@ static void CreateHostDevice()
g_samplerDescriptorSet = descriptorSetBuilder.create(g_device.get()); g_samplerDescriptorSet = descriptorSetBuilder.create(g_device.get());
pipelineLayoutBuilder.addDescriptorSet(descriptorSetBuilder); pipelineLayoutBuilder.addDescriptorSet(descriptorSetBuilder);
pipelineLayoutBuilder.addRootDescriptor(0, 4, RenderRootDescriptorType::CONSTANT_BUFFER); if (g_vulkan)
pipelineLayoutBuilder.addRootDescriptor(1, 4, RenderRootDescriptorType::CONSTANT_BUFFER); {
pipelineLayoutBuilder.addRootDescriptor(2, 4, RenderRootDescriptorType::CONSTANT_BUFFER); pipelineLayoutBuilder.addPushConstant(0, 4, 24, RenderShaderStageFlag::VERTEX | RenderShaderStageFlag::PIXEL);
}
else
{
pipelineLayoutBuilder.addRootDescriptor(0, 4, RenderRootDescriptorType::CONSTANT_BUFFER);
pipelineLayoutBuilder.addRootDescriptor(1, 4, RenderRootDescriptorType::CONSTANT_BUFFER);
pipelineLayoutBuilder.addRootDescriptor(2, 4, RenderRootDescriptorType::CONSTANT_BUFFER);
}
pipelineLayoutBuilder.end(); pipelineLayoutBuilder.end();
g_pipelineLayout = pipelineLayoutBuilder.create(g_device.get()); g_pipelineLayout = pipelineLayoutBuilder.create(g_device.get());
@ -528,9 +545,9 @@ static void BeginCommandList()
g_pipelineState.renderTargetFormat = g_backBuffer->format; g_pipelineState.renderTargetFormat = g_backBuffer->format;
g_pipelineState.depthStencilFormat = RenderFormat::UNKNOWN; g_pipelineState.depthStencilFormat = RenderFormat::UNKNOWN;
uint32_t textureIndex = 0; bool acquired = g_swapChain->acquireTexture(g_acquireSemaphores[g_frame].get(), &g_backBufferIndex);
g_swapChain->acquireTexture(nullptr, &textureIndex); assert(acquired);
g_backBuffer->texture = g_swapChain->getTexture(textureIndex); g_backBuffer->texture = g_swapChain->getTexture(g_backBufferIndex);
auto& commandList = g_commandLists[g_frame]; auto& commandList = g_commandLists[g_frame];
@ -779,9 +796,22 @@ static void Present()
auto& commandList = g_commandLists[g_frame]; auto& commandList = g_commandLists[g_frame];
commandList->barriers(RenderBarrierStage::GRAPHICS, RenderTextureBarrier(g_backBuffer->texture, RenderTextureLayout::PRESENT)); commandList->barriers(RenderBarrierStage::GRAPHICS, RenderTextureBarrier(g_backBuffer->texture, RenderTextureLayout::PRESENT));
commandList->end(); commandList->end();
g_queue->executeCommandLists(commandList.get(), g_commandFences[g_frame].get()); if (g_vulkan)
g_swapChain->present(0, nullptr, 0); {
const RenderCommandList* commandLists[] = { commandList.get() };
RenderCommandSemaphore* waitSemaphores[] = { g_acquireSemaphores[g_frame].get()};
g_queue->executeCommandLists(
commandLists, std::size(commandLists),
waitSemaphores, std::size(waitSemaphores),
nullptr, 0,
g_commandFences[g_frame].get());
}
else
{
g_queue->executeCommandLists(commandList.get(), g_commandFences[g_frame].get());
}
g_swapChain->present(g_backBufferIndex, nullptr, 0);
g_frame = g_nextFrame; g_frame = g_nextFrame;
g_nextFrame = (g_frame + 1) % NUM_FRAMES; g_nextFrame = (g_frame + 1) % NUM_FRAMES;
@ -856,10 +886,11 @@ static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t dep
desc.mipLevels = levels; desc.mipLevels = levels;
desc.arraySize = 1; desc.arraySize = 1;
desc.format = ConvertFormat(format); desc.format = ConvertFormat(format);
desc.flags = (desc.format == RenderFormat::D32_FLOAT) ? RenderTextureFlag::DEPTH_TARGET : RenderTextureFlag::NONE;
texture->texture = g_device->createTexture(desc); texture->texture = g_device->createTexture(desc);
RenderTextureViewDesc viewDesc; RenderTextureViewDesc viewDesc;
viewDesc.format = desc.format == RenderFormat::D32_FLOAT ? RenderFormat::R32_FLOAT : desc.format; viewDesc.format = desc.format;
viewDesc.dimension = texture->type == ResourceType::VolumeTexture ? RenderTextureViewDimension::TEXTURE_3D : RenderTextureViewDimension::TEXTURE_2D; viewDesc.dimension = texture->type == ResourceType::VolumeTexture ? RenderTextureViewDimension::TEXTURE_3D : RenderTextureViewDimension::TEXTURE_2D;
viewDesc.mipLevels = levels; viewDesc.mipLevels = levels;
texture->textureView = texture->texture->createTextureView(viewDesc); texture->textureView = texture->texture->createTextureView(viewDesc);
@ -878,7 +909,7 @@ static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t dep
static GuestBuffer* CreateVertexBuffer(uint32_t length) static GuestBuffer* CreateVertexBuffer(uint32_t length)
{ {
auto buffer = g_userHeap.AllocPhysical<GuestBuffer>(ResourceType::VertexBuffer); auto buffer = g_userHeap.AllocPhysical<GuestBuffer>(ResourceType::VertexBuffer);
buffer->buffer = g_device->createBuffer(RenderBufferDesc::VertexBuffer(length, RenderHeapType::DEFAULT)); buffer->buffer = g_device->createBuffer(RenderBufferDesc::VertexBuffer(length, RenderHeapType::DEFAULT, RenderBufferFlag::INDEX));
buffer->dataSize = length; buffer->dataSize = length;
#ifdef _DEBUG #ifdef _DEBUG
buffer->buffer->setName(std::format("Vertex Buffer {:X}", g_memory.MapVirtual(buffer))); buffer->buffer->setName(std::format("Vertex Buffer {:X}", g_memory.MapVirtual(buffer)));
@ -1204,7 +1235,7 @@ static void FlushRenderState(GuestDevice* device)
constexpr size_t BOOL_MASK = 0x100000000000000ull; constexpr size_t BOOL_MASK = 0x100000000000000ull;
if ((device->dirtyFlags[4].get() & BOOL_MASK) != 0) if ((device->dirtyFlags[4].get() & BOOL_MASK) != 0)
{ {
uint32_t booleans = device->vertexShaderBoolConstants [0].get() & 0xFF; uint32_t booleans = device->vertexShaderBoolConstants[0].get() & 0xFF;
booleans |= (device->pixelShaderBoolConstants[0].get() & 0xFF) << 16; booleans |= (device->pixelShaderBoolConstants[0].get() & 0xFF) << 16;
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.booleans, booleans); SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.booleans, booleans);
@ -1250,15 +1281,30 @@ static void FlushRenderState(GuestDevice* device)
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.samplerIndices[i], descriptorIndex); SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.samplerIndices[i], descriptorIndex);
} }
device->dirtyFlags[3] = device->dirtyFlags[3].get() & ~mask;
} }
} }
auto& uploadAllocator = g_uploadAllocators[g_frame]; auto& uploadAllocator = g_uploadAllocators[g_frame];
auto setRootDescriptor = [&](RenderBufferReference reference, size_t index)
{
if (g_vulkan)
{
uint64_t address = reference.ref->getDeviceAddress() + reference.offset;
commandList->setGraphicsPushConstants(0, &address, 8 * index, 8);
}
else
{
commandList->setGraphicsRootDescriptor(reference, index);
}
};
if (g_dirtyStates.sharedConstants) if (g_dirtyStates.sharedConstants)
{ {
auto sharedConstants = uploadAllocator.allocate<false>(&g_sharedConstants, sizeof(g_sharedConstants), 0x100); auto sharedConstants = uploadAllocator.allocate<false>(&g_sharedConstants, sizeof(g_sharedConstants), 0x100);
commandList->setGraphicsRootDescriptor(sharedConstants, 2); setRootDescriptor(sharedConstants, 2);
} }
if (g_dirtyStates.scissorRect) if (g_dirtyStates.scissorRect)
@ -1275,8 +1321,7 @@ static void FlushRenderState(GuestDevice* device)
if (g_dirtyStates.vertexShaderConstants || device->dirtyFlags[0] != 0) if (g_dirtyStates.vertexShaderConstants || device->dirtyFlags[0] != 0)
{ {
auto vertexShaderConstants = uploadAllocator.allocate<true>(device->vertexShaderFloatConstants, 0x1000, 0x100); auto vertexShaderConstants = uploadAllocator.allocate<true>(device->vertexShaderFloatConstants, 0x1000, 0x100);
commandList->setGraphicsRootDescriptor(vertexShaderConstants, 0); setRootDescriptor(vertexShaderConstants, 0);
device->dirtyFlags[0] = 0; device->dirtyFlags[0] = 0;
} }
@ -1289,14 +1334,13 @@ static void FlushRenderState(GuestDevice* device)
g_inputSlots + g_dirtyStates.vertexStreamFirst); g_inputSlots + g_dirtyStates.vertexStreamFirst);
} }
if (g_dirtyStates.indices) if (g_dirtyStates.indices && (!g_vulkan || g_indexBufferView.buffer.ref != nullptr))
commandList->setIndexBuffer(&g_indexBufferView); commandList->setIndexBuffer(&g_indexBufferView);
if (g_dirtyStates.pixelShaderConstants || device->dirtyFlags[1] != 0) if (g_dirtyStates.pixelShaderConstants || device->dirtyFlags[1] != 0)
{ {
auto pixelShaderConstants = uploadAllocator.allocate<true>(device->pixelShaderFloatConstants, 0xE00, 0x100); auto pixelShaderConstants = uploadAllocator.allocate<true>(device->pixelShaderFloatConstants, 0xE00, 0x100);
commandList->setGraphicsRootDescriptor(pixelShaderConstants, 1); setRootDescriptor(pixelShaderConstants, 1);
device->dirtyFlags[1] = 0; device->dirtyFlags[1] = 0;
} }
@ -1555,14 +1599,60 @@ static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* verte
static std::vector<RenderInputElement> inputElements; static std::vector<RenderInputElement> inputElements;
inputElements.clear(); inputElements.clear();
struct Location
{
uint32_t usage;
uint32_t usageIndex;
uint32_t location;
};
constexpr Location locations[] =
{
{ D3DDECLUSAGE_POSITION, 0, 0 },
{ D3DDECLUSAGE_NORMAL, 0, 1 },
{ D3DDECLUSAGE_TANGENT, 0, 2 },
{ D3DDECLUSAGE_BINORMAL, 0, 3 },
{ D3DDECLUSAGE_TEXCOORD, 0, 4 },
{ D3DDECLUSAGE_TEXCOORD, 1, 5 },
{ D3DDECLUSAGE_TEXCOORD, 2, 6 },
{ D3DDECLUSAGE_TEXCOORD, 3, 7 },
{ D3DDECLUSAGE_COLOR, 0, 8 },
{ D3DDECLUSAGE_BLENDINDICES, 0, 9 },
{ D3DDECLUSAGE_BLENDWEIGHT, 0, 10 },
{ D3DDECLUSAGE_COLOR, 1, 11 },
{ D3DDECLUSAGE_TEXCOORD, 4, 12 },
{ D3DDECLUSAGE_TEXCOORD, 5, 13 },
{ D3DDECLUSAGE_TEXCOORD, 6, 14 },
{ D3DDECLUSAGE_TEXCOORD, 7, 15 },
{ D3DDECLUSAGE_POSITION, 1, 15 }
};
vertexElement = vertexElements; vertexElement = vertexElements;
while (vertexElement->stream != 0xFF && vertexElement->type != D3DDECLTYPE_UNUSED) while (vertexElement->stream != 0xFF && vertexElement->type != D3DDECLTYPE_UNUSED)
{ {
if (vertexElement->usage == D3DDECLUSAGE_POSITION && vertexElement->usageIndex == 2)
{
++vertexElement;
continue;
}
auto& inputElement = inputElements.emplace_back(); auto& inputElement = inputElements.emplace_back();
inputElement.semanticName = ConvertDeclUsage(vertexElement->usage); inputElement.semanticName = ConvertDeclUsage(vertexElement->usage);
inputElement.semanticIndex = vertexElement->usageIndex; inputElement.semanticIndex = vertexElement->usageIndex;
inputElement.location = (vertexElement->usage * 4) + vertexElement->usageIndex; inputElement.location = ~0;
for (auto& location : locations)
{
if (location.usage == vertexElement->usage && location.usageIndex == vertexElement->usageIndex)
{
inputElement.location = location.location;
break;
}
}
assert(inputElement.location != ~0);
inputElement.format = ConvertDeclType(vertexElement->type); inputElement.format = ConvertDeclType(vertexElement->type);
inputElement.slotIndex = vertexElement->stream; inputElement.slotIndex = vertexElement->stream;
inputElement.alignedByteOffset = vertexElement->offset; inputElement.alignedByteOffset = vertexElement->offset;
@ -1611,7 +1701,18 @@ static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* verte
auto addInputElement = [&](uint32_t usage, uint32_t usageIndex) auto addInputElement = [&](uint32_t usage, uint32_t usageIndex)
{ {
uint32_t location = (usage * 4) + usageIndex; uint32_t location = ~0;
for (auto& alsoLocation : locations)
{
if (alsoLocation.usage == usage && alsoLocation.usageIndex == usageIndex)
{
location = alsoLocation.location;
break;
}
}
assert(location != ~0);
for (auto& inputElement : inputElements) for (auto& inputElement : inputElements)
{ {
@ -1642,7 +1743,6 @@ static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* verte
addInputElement(D3DDECLUSAGE_TEXCOORD, 2); addInputElement(D3DDECLUSAGE_TEXCOORD, 2);
addInputElement(D3DDECLUSAGE_TEXCOORD, 3); addInputElement(D3DDECLUSAGE_TEXCOORD, 3);
addInputElement(D3DDECLUSAGE_COLOR, 0); addInputElement(D3DDECLUSAGE_COLOR, 0);
addInputElement(D3DDECLUSAGE_COLOR, 1);
addInputElement(D3DDECLUSAGE_BLENDWEIGHT, 0); addInputElement(D3DDECLUSAGE_BLENDWEIGHT, 0);
addInputElement(D3DDECLUSAGE_BLENDINDICES, 0); addInputElement(D3DDECLUSAGE_BLENDINDICES, 0);
@ -1671,11 +1771,30 @@ static void SetVertexDeclaration(GuestDevice* device, GuestVertexDeclaration* ve
device->vertexDeclaration = vertexDeclaration; device->vertexDeclaration = vertexDeclaration;
} }
static std::unique_ptr<RenderShader> CreateShader(const uint32_t* function)
{
if (*function == 0)
{
const uint32_t dxilSize = *(function + 1);
const uint32_t spirvSize = *(function + 2);
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(function + 3);
if (g_vulkan)
{
return g_device->createShader(bytes + dxilSize, spirvSize, "main", RenderShaderFormat::SPIRV);
}
else
{
return g_device->createShader(bytes, dxilSize, "main", RenderShaderFormat::DXIL);
}
}
return nullptr;
}
static GuestShader* CreateVertexShader(const uint32_t* function) static GuestShader* CreateVertexShader(const uint32_t* function)
{ {
auto vertexShader = g_userHeap.AllocPhysical<GuestShader>(ResourceType::VertexShader); auto vertexShader = g_userHeap.AllocPhysical<GuestShader>(ResourceType::VertexShader);
if (*function == 0x43425844) vertexShader->shader = CreateShader(function);
vertexShader->shader = g_device->createShader(function, function[6], "main", RenderShaderFormat::DXIL);
return vertexShader; return vertexShader;
} }
@ -1705,15 +1824,14 @@ static void SetStreamSource(GuestDevice* device, uint32_t index, GuestBuffer* bu
static void SetIndices(GuestDevice* device, GuestBuffer* buffer) static void SetIndices(GuestDevice* device, GuestBuffer* buffer)
{ {
SetDirtyValue(g_dirtyStates.indices, g_indexBufferView.buffer, buffer != nullptr ? buffer->buffer->at(0) : RenderBufferReference{}); SetDirtyValue(g_dirtyStates.indices, g_indexBufferView.buffer, buffer != nullptr ? buffer->buffer->at(0) : RenderBufferReference{});
SetDirtyValue(g_dirtyStates.indices, g_indexBufferView.format, buffer != nullptr ? buffer->format : RenderFormat::UNKNOWN); SetDirtyValue(g_dirtyStates.indices, g_indexBufferView.format, buffer != nullptr ? buffer->format : RenderFormat::R16_UINT);
SetDirtyValue(g_dirtyStates.indices, g_indexBufferView.size, buffer != nullptr ? buffer->dataSize : 0u); SetDirtyValue(g_dirtyStates.indices, g_indexBufferView.size, buffer != nullptr ? buffer->dataSize : 0u);
} }
static GuestShader* CreatePixelShader(const uint32_t* function) static GuestShader* CreatePixelShader(const uint32_t* function)
{ {
auto pixelShader = g_userHeap.AllocPhysical<GuestShader>(ResourceType::PixelShader); auto pixelShader = g_userHeap.AllocPhysical<GuestShader>(ResourceType::PixelShader);
if (*function == 0x43425844) pixelShader->shader = CreateShader(function);
pixelShader->shader = g_device->createShader(function, function[6], "main", RenderShaderFormat::DXIL);
return pixelShader; return pixelShader;
} }
@ -2031,6 +2149,7 @@ static void MakePictureData(GuestPictureData* pictureData, uint8_t* data, uint32
desc.mipLevels = ddsDesc.numMips; desc.mipLevels = ddsDesc.numMips;
desc.arraySize = ddsDesc.type == ddspp::TextureType::Cubemap ? ddsDesc.arraySize * 6 : ddsDesc.arraySize; desc.arraySize = ddsDesc.type == ddspp::TextureType::Cubemap ? ddsDesc.arraySize * 6 : ddsDesc.arraySize;
desc.format = ConvertDXGIFormat(ddsDesc.format); desc.format = ConvertDXGIFormat(ddsDesc.format);
desc.flags = ddsDesc.type == ddspp::TextureType::Cubemap ? RenderTextureFlag::CUBE : RenderTextureFlag::NONE;
texture->texture = g_device->createTexture(desc); texture->texture = g_device->createTexture(desc);
#ifdef _DEBUG #ifdef _DEBUG
texture->texture->setName(reinterpret_cast<char*>(g_memory.Translate(pictureData->name + 2))); texture->texture->setName(reinterpret_cast<char*>(g_memory.Translate(pictureData->name + 2)));
@ -2108,6 +2227,8 @@ static void MakePictureData(GuestPictureData* pictureData, uint8_t* data, uint32
ExecuteCopyCommandList([&] ExecuteCopyCommandList([&]
{ {
g_copyCommandList->barriers(RenderBarrierStage::COPY, RenderTextureBarrier(texture->texture.get(), RenderTextureLayout::COPY_DEST));
for (size_t i = 0; i < slices.size(); i++) for (size_t i = 0; i < slices.size(); i++)
{ {
auto& slice = slices[i]; auto& slice = slices[i];

1
thirdparty/Vulkan-Headers vendored Submodule

@ -0,0 +1 @@
Subproject commit 14345dab231912ee9601136e96ca67a6e1f632e7

1
thirdparty/VulkanMemoryAllocator vendored Submodule

@ -0,0 +1 @@
Subproject commit 1c35ba99ce775f8342d87a83a3f0f696f99c2a39

1
thirdparty/volk vendored Submodule

@ -0,0 +1 @@
Subproject commit 447e21b5d92ed8d5271b0d39b071f938fcfa875f