Implement Maxwell3D Sampled Textures

The descriptor sets should now contain a combined image and sampler handle for any sampled textures in the guest shader from the supplied offset into the texture constant buffer.

Note: Games tend to rely on inline constant buffer updates for writing the texture constant buffer and due to it not being implemented, the value will be read as 0 which is incorrect.
This commit is contained in:
PixelyIon 2022-01-06 00:59:54 +05:30
parent d9a9e52350
commit bb14af4f7a
5 changed files with 62 additions and 3 deletions

View File

@ -10,12 +10,16 @@ namespace skyline::gpu {
void DescriptorAllocator::AllocateDescriptorPool() {
namespace maxwell3d = soc::gm20b::engine::maxwell3d::type; // We use Maxwell3D as reference for base descriptor counts
using DescriptorSizes = std::array<vk::DescriptorPoolSize, 1>;
using DescriptorSizes = std::array<vk::DescriptorPoolSize, 2>;
constexpr DescriptorSizes BaseDescriptorSizes{
vk::DescriptorPoolSize{
.descriptorCount = maxwell3d::PipelineStageConstantBufferCount,
.type = vk::DescriptorType::eUniformBuffer,
},
vk::DescriptorPoolSize{
.descriptorCount = maxwell3d::PipelineStageCount * 20,
.type = vk::DescriptorType::eCombinedImageSampler,
},
};
DescriptorSizes descriptorSizes{BaseDescriptorSizes};

View File

@ -45,6 +45,10 @@ namespace skyline::gpu::interconnect {
}
}
void CommandExecutor::AttachDependency(std::shared_ptr<FenceCycleDependency> dependency) {
cycle->AttachObject(dependency);
}
void CommandExecutor::AddSubpass(std::function<void(vk::raii::CommandBuffer &, const std::shared_ptr<FenceCycle> &, GPU &, vk::RenderPass, u32)> &&function, vk::Rect2D renderArea, span<TextureView *> inputAttachments, span<TextureView *> colorAttachments, TextureView *depthStencilAttachment) {
for (const auto &attachments : {inputAttachments, colorAttachments})
for (const auto &attachment : attachments)

View File

@ -46,6 +46,11 @@ namespace skyline::gpu::interconnect {
*/
void AttachBuffer(BufferView *view);
/**
* @brief Attach the lifetime of the fence cycle dependency to the command buffer
*/
void AttachDependency(std::shared_ptr<FenceCycleDependency> dependency);
/**
* @brief Adds a command that needs to be executed inside a subpass configured with certain attachments
* @note Any texture supplied to this **must** be locked by the calling thread, it should also undergo no persistent layout transitions till execution

View File

@ -679,13 +679,14 @@ namespace skyline::gpu::interconnect {
constexpr static size_t MaxShaderBytecodeSize{1 * 1024 * 1024}; //!< The largest shader binary that we support (1 MiB)
constexpr static size_t PipelineUniqueDescriptorTypeCount{1}; //!< The amount of unique descriptor types that may be bound to a pipeline
constexpr static size_t PipelineUniqueDescriptorTypeCount{2}; //!< The amount of unique descriptor types that may be bound to a pipeline
constexpr static size_t MaxPipelineDescriptorWriteCount{maxwell3d::PipelineStageCount * PipelineUniqueDescriptorTypeCount}; //!< The maxium amount of descriptors writes that are used to bind a pipeline
constexpr static size_t MaxPipelineDescriptorCount{100}; //!< The maxium amount of descriptors we support being bound to a pipeline
boost::container::static_vector<vk::WriteDescriptorSet, MaxPipelineDescriptorWriteCount> descriptorSetWrites;
boost::container::static_vector<vk::DescriptorSetLayoutBinding, MaxPipelineDescriptorCount> layoutBindings;
boost::container::static_vector<vk::DescriptorBufferInfo, MaxPipelineDescriptorCount> bufferInfo;
boost::container::static_vector<vk::DescriptorImageInfo, MaxPipelineDescriptorCount> imageInfo;
/**
* @brief All state concerning the shader programs and their bindings
@ -799,6 +800,11 @@ namespace skyline::gpu::interconnect {
}
}
descriptorSetWrites.clear();
layoutBindings.clear();
bufferInfo.clear();
imageInfo.clear();
runtimeInfo.previous_stage_stores.mask.set(); // First stage should always have all bits set
ShaderCompiler::Backend::Bindings bindings{};
@ -852,6 +858,46 @@ namespace skyline::gpu::interconnect {
}
}
if (!program.info.texture_descriptors.empty()) {
descriptorSetWrites.push_back(vk::WriteDescriptorSet{
.dstBinding = bindingIndex,
.descriptorCount = static_cast<u32>(program.info.texture_descriptors.size()),
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.pImageInfo = imageInfo.data() + imageInfo.size(),
});
u32 descriptorIndex{};
for (auto &texture : program.info.texture_descriptors) {
layoutBindings.push_back(vk::DescriptorSetLayoutBinding{
.binding = bindingIndex++,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = 1,
.stageFlags = pipelineStage.vkStage,
});
auto &constantBuffer{pipelineStage.constantBuffers[texture.cbuf_index]};
union TextureHandle {
u32 raw;
struct {
u32 textureIndex : 20;
u32 samplerIndex : 12;
};
} handle{constantBuffer.Read<u32>(texture.cbuf_offset + (descriptorIndex++ << texture.size_shift))};
auto sampler{GetSampler(handle.samplerIndex)};
auto textureView{GetPoolTextureView(handle.textureIndex)};
std::scoped_lock lock(*textureView);
imageInfo.push_back(vk::DescriptorImageInfo{
.sampler = **sampler,
.imageView = textureView->GetView(),
.imageLayout = textureView->texture->layout,
});
executor.AttachTexture(textureView.get());
executor.AttachDependency(std::move(sampler));
}
}
shaderStagesInfo[count++] = vk::PipelineShaderStageCreateInfo{
.stage = pipelineStage.vkStage,
.module = **pipelineStage.vkModule,

View File

@ -259,7 +259,7 @@ namespace skyline::gpu {
mipLevels(1),
layerCount(guest->layerCount),
sampleCount(vk::SampleCountFlagBits::e1) {
vk::ImageUsageFlags usage{vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst};
vk::ImageUsageFlags usage{vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled};
if (format->vkAspect & vk::ImageAspectFlagBits::eColor)
usage |= vk::ImageUsageFlagBits::eColorAttachment;
if (format->vkAspect & (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil))