renderer_vulkan: Use combined image samplers
* Less descriptors = good
This commit is contained in:
@ -47,7 +47,7 @@ template <typename T>
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
requires std::is_unsigned_v<T>
|
requires std::is_unsigned_v<T>
|
||||||
[[nodiscard]] constexpr bool IsPow2(T value) {
|
[[nodiscard]] constexpr bool IsPow2(T value) {
|
||||||
return std::has_single_bit(value);
|
return value != 0 && (value & (value - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -64,7 +64,6 @@ bool DecodePNG(std::span<const u8> png_data, std::span<u8> out_data) {
|
|||||||
if (spng_decoded_image_size(ctx.get(), format, &decoded_len)) {
|
if (spng_decoded_image_size(ctx.get(), format, &decoded_len)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ASSERT(out_data.size() == decoded_len);
|
|
||||||
|
|
||||||
if (spng_decode_image(ctx.get(), out_data.data(), decoded_len, format, 0)) {
|
if (spng_decode_image(ctx.get(), out_data.data(), decoded_len, format, 0)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -18,9 +18,8 @@ layout (push_constant, std140) uniform DrawInfo {
|
|||||||
int reverse_interlaced;
|
int reverse_interlaced;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (set = 0, binding = 0) uniform texture2D screen_textures[3];
|
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
|
||||||
layout (set = 0, binding = 1) uniform sampler screen_sampler;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
color = texture(sampler2D(screen_textures[screen_id_l], screen_sampler), frag_tex_coord);
|
color = texture(screen_textures[screen_id_l], frag_tex_coord);
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,10 @@ layout (push_constant, std140) uniform DrawInfo {
|
|||||||
int reverse_interlaced;
|
int reverse_interlaced;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (set = 0, binding = 0) uniform texture2D screen_textures[3];
|
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
|
||||||
layout (set = 0, binding = 1) uniform sampler screen_sampler;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 color_tex_l = texture(sampler2D(screen_textures[screen_id_l], screen_sampler), frag_tex_coord);
|
vec4 color_tex_l = texture(screen_textures[screen_id_l], frag_tex_coord);
|
||||||
vec4 color_tex_r = texture(sampler2D(screen_textures[screen_id_r], screen_sampler), frag_tex_coord);
|
vec4 color_tex_r = texture(screen_textures[screen_id_r], frag_tex_coord);
|
||||||
color = vec4(color_tex_l.rgb*l+color_tex_r.rgb*r, color_tex_l.a);
|
color = vec4(color_tex_l.rgb*l+color_tex_r.rgb*r, color_tex_l.a);
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,12 @@ layout (push_constant, std140) uniform DrawInfo {
|
|||||||
int reverse_interlaced;
|
int reverse_interlaced;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (set = 0, binding = 0) uniform texture2D screen_textures[3];
|
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
|
||||||
layout (set = 0, binding = 1) uniform sampler screen_sampler;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float screen_row = o_resolution.x * frag_tex_coord.x;
|
float screen_row = o_resolution.x * frag_tex_coord.x;
|
||||||
if (int(screen_row) % 2 == reverse_interlaced)
|
if (int(screen_row) % 2 == reverse_interlaced)
|
||||||
color = texture(sampler2D(screen_textures[screen_id_l], screen_sampler), frag_tex_coord);
|
color = texture(screen_textures[screen_id_l], frag_tex_coord);
|
||||||
else
|
else
|
||||||
color = texture(sampler2D(screen_textures[screen_id_r], screen_sampler), frag_tex_coord);
|
color = texture(screen_textures[screen_id_r], frag_tex_coord);
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ void CustomTexManager::DecodeToStaging(const Texture& texture, const StagingData
|
|||||||
}
|
}
|
||||||
if (compatibility_mode) {
|
if (compatibility_mode) {
|
||||||
const u32 stride = texture.width * 4;
|
const u32 stride = texture.width * 4;
|
||||||
// FlipTexture(staging.mapped, texture.width, texture.height, stride);
|
FlipTexture(staging.mapped, texture.width, texture.height, stride);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CustomFileFormat::DDS:
|
case CustomFileFormat::DDS:
|
||||||
|
@ -1538,7 +1538,7 @@ do {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out += '}';
|
out += '}';
|
||||||
|
LOG_INFO(Render_OpenGL, "{}", out);
|
||||||
return {std::move(out)};
|
return {std::move(out)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,11 +226,11 @@ void RendererVulkan::BeginRendering(Frame* frame) {
|
|||||||
for (std::size_t i = 0; i < screen_infos.size(); i++) {
|
for (std::size_t i = 0; i < screen_infos.size(); i++) {
|
||||||
const auto& info = screen_infos[i];
|
const auto& info = screen_infos[i];
|
||||||
present_textures[i] = vk::DescriptorImageInfo{
|
present_textures[i] = vk::DescriptorImageInfo{
|
||||||
|
.sampler = present_samplers[current_sampler],
|
||||||
.imageView = info.image_view,
|
.imageView = info.image_view,
|
||||||
.imageLayout = vk::ImageLayout::eGeneral,
|
.imageLayout = vk::ImageLayout::eGeneral,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
present_textures[3].sampler = present_samplers[current_sampler];
|
|
||||||
|
|
||||||
vk::DescriptorSet set = desc_manager.AllocateSet(present_descriptor_layout);
|
vk::DescriptorSet set = desc_manager.AllocateSet(present_descriptor_layout);
|
||||||
instance.GetDevice().updateDescriptorSetWithTemplate(set, present_update_template,
|
instance.GetDevice().updateDescriptorSetWithTemplate(set, present_update_template,
|
||||||
@ -320,51 +320,33 @@ void RendererVulkan::CompileShaders() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RendererVulkan::BuildLayouts() {
|
void RendererVulkan::BuildLayouts() {
|
||||||
const std::array present_layout_bindings = {
|
const vk::DescriptorSetLayoutBinding present_layout_binding = {
|
||||||
vk::DescriptorSetLayoutBinding{
|
.binding = 0,
|
||||||
.binding = 0,
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.descriptorType = vk::DescriptorType::eSampledImage,
|
.descriptorCount = 3,
|
||||||
.descriptorCount = 3,
|
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
|
||||||
},
|
|
||||||
vk::DescriptorSetLayoutBinding{
|
|
||||||
.binding = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eSampler,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const vk::DescriptorSetLayoutCreateInfo present_layout_info = {
|
const vk::DescriptorSetLayoutCreateInfo present_layout_info = {
|
||||||
.bindingCount = static_cast<u32>(present_layout_bindings.size()),
|
.bindingCount = 1,
|
||||||
.pBindings = present_layout_bindings.data(),
|
.pBindings = &present_layout_binding,
|
||||||
};
|
};
|
||||||
|
|
||||||
const vk::Device device = instance.GetDevice();
|
const vk::Device device = instance.GetDevice();
|
||||||
present_descriptor_layout = device.createDescriptorSetLayout(present_layout_info);
|
present_descriptor_layout = device.createDescriptorSetLayout(present_layout_info);
|
||||||
|
|
||||||
const std::array update_template_entries = {
|
const vk::DescriptorUpdateTemplateEntry update_template_entry = {
|
||||||
vk::DescriptorUpdateTemplateEntry{
|
.dstBinding = 0,
|
||||||
.dstBinding = 0,
|
.dstArrayElement = 0,
|
||||||
.dstArrayElement = 0,
|
.descriptorCount = 3,
|
||||||
.descriptorCount = 3,
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.descriptorType = vk::DescriptorType::eSampledImage,
|
.offset = 0,
|
||||||
.offset = 0,
|
.stride = sizeof(vk::DescriptorImageInfo),
|
||||||
.stride = sizeof(vk::DescriptorImageInfo),
|
|
||||||
},
|
|
||||||
vk::DescriptorUpdateTemplateEntry{
|
|
||||||
.dstBinding = 1,
|
|
||||||
.dstArrayElement = 0,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eSampler,
|
|
||||||
.offset = 3 * sizeof(vk::DescriptorImageInfo),
|
|
||||||
.stride = 0,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const vk::DescriptorUpdateTemplateCreateInfo template_info = {
|
const vk::DescriptorUpdateTemplateCreateInfo template_info = {
|
||||||
.descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()),
|
.descriptorUpdateEntryCount = 1,
|
||||||
.pDescriptorUpdateEntries = update_template_entries.data(),
|
.pDescriptorUpdateEntries = &update_template_entry,
|
||||||
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
|
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
|
||||||
.descriptorSetLayout = present_descriptor_layout,
|
.descriptorSetLayout = present_descriptor_layout,
|
||||||
};
|
};
|
||||||
|
@ -165,7 +165,7 @@ private:
|
|||||||
|
|
||||||
/// Display information for top and bottom screens respectively
|
/// Display information for top and bottom screens respectively
|
||||||
std::array<ScreenInfo, 3> screen_infos{};
|
std::array<ScreenInfo, 3> screen_infos{};
|
||||||
std::array<vk::DescriptorImageInfo, 4> present_textures{};
|
std::array<vk::DescriptorImageInfo, 3> present_textures{};
|
||||||
PresentUniformData draw_info{};
|
PresentUniformData draw_info{};
|
||||||
vk::ClearColorValue clear_color{};
|
vk::ClearColorValue clear_color{};
|
||||||
};
|
};
|
||||||
|
@ -31,21 +31,10 @@ constexpr static std::array RASTERIZER_SETS = {
|
|||||||
// Texture set
|
// Texture set
|
||||||
.bindings =
|
.bindings =
|
||||||
{
|
{
|
||||||
vk::DescriptorType::eSampledImage,
|
vk::DescriptorType::eCombinedImageSampler,
|
||||||
vk::DescriptorType::eSampledImage,
|
vk::DescriptorType::eCombinedImageSampler,
|
||||||
vk::DescriptorType::eSampledImage,
|
vk::DescriptorType::eCombinedImageSampler,
|
||||||
vk::DescriptorType::eSampledImage,
|
vk::DescriptorType::eCombinedImageSampler,
|
||||||
},
|
|
||||||
.binding_count = 4,
|
|
||||||
},
|
|
||||||
Bindings{
|
|
||||||
// Sampler set
|
|
||||||
.bindings =
|
|
||||||
{
|
|
||||||
vk::DescriptorType::eSampler,
|
|
||||||
vk::DescriptorType::eSampler,
|
|
||||||
vk::DescriptorType::eSampler,
|
|
||||||
vk::DescriptorType::eSampler,
|
|
||||||
},
|
},
|
||||||
.binding_count = 4,
|
.binding_count = 4,
|
||||||
},
|
},
|
||||||
@ -76,6 +65,7 @@ constexpr vk::ShaderStageFlags ToVkStageFlags(vk::DescriptorType type) {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case vk::DescriptorType::eSampler:
|
case vk::DescriptorType::eSampler:
|
||||||
case vk::DescriptorType::eSampledImage:
|
case vk::DescriptorType::eSampledImage:
|
||||||
|
case vk::DescriptorType::eCombinedImageSampler:
|
||||||
case vk::DescriptorType::eUniformTexelBuffer:
|
case vk::DescriptorType::eUniformTexelBuffer:
|
||||||
case vk::DescriptorType::eStorageImage:
|
case vk::DescriptorType::eStorageImage:
|
||||||
flags = vk::ShaderStageFlagBits::eFragment;
|
flags = vk::ShaderStageFlagBits::eFragment;
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
constexpr u32 MAX_DESCRIPTORS = 8;
|
constexpr u32 MAX_DESCRIPTORS = 7;
|
||||||
constexpr u32 MAX_DESCRIPTOR_SETS = 4;
|
constexpr u32 MAX_DESCRIPTOR_SETS = 3;
|
||||||
|
|
||||||
union DescriptorData {
|
union DescriptorData {
|
||||||
vk::DescriptorImageInfo image_info;
|
vk::DescriptorImageInfo image_info;
|
||||||
|
@ -635,8 +635,9 @@ void PipelineCache::UseFragmentShader(const Pica::Regs& regs) {
|
|||||||
shader_hashes[ProgramType::FS] = config.Hash();
|
shader_hashes[ProgramType::FS] = config.Hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipelineCache::BindTexture(u32 binding, vk::ImageView image_view) {
|
void PipelineCache::BindTexture(u32 binding, vk::ImageView image_view, vk::Sampler sampler) {
|
||||||
const vk::DescriptorImageInfo image_info = {
|
const vk::DescriptorImageInfo image_info = {
|
||||||
|
.sampler = sampler,
|
||||||
.imageView = image_view,
|
.imageView = image_view,
|
||||||
.imageLayout = vk::ImageLayout::eGeneral,
|
.imageLayout = vk::ImageLayout::eGeneral,
|
||||||
};
|
};
|
||||||
@ -648,7 +649,7 @@ void PipelineCache::BindStorageImage(u32 binding, vk::ImageView image_view) {
|
|||||||
.imageView = image_view,
|
.imageView = image_view,
|
||||||
.imageLayout = vk::ImageLayout::eGeneral,
|
.imageLayout = vk::ImageLayout::eGeneral,
|
||||||
};
|
};
|
||||||
desc_manager.SetBinding(3, binding, DescriptorData{image_info});
|
desc_manager.SetBinding(2, binding, DescriptorData{image_info});
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipelineCache::BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size) {
|
void PipelineCache::BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size) {
|
||||||
@ -670,16 +671,6 @@ void PipelineCache::BindTexelBuffer(u32 binding, vk::BufferView buffer_view) {
|
|||||||
desc_manager.SetBinding(0, binding, data);
|
desc_manager.SetBinding(0, binding, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipelineCache::BindSampler(u32 binding, vk::Sampler sampler) {
|
|
||||||
const DescriptorData data = {
|
|
||||||
.image_info =
|
|
||||||
vk::DescriptorImageInfo{
|
|
||||||
.sampler = sampler,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
desc_manager.SetBinding(2, binding, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PipelineCache::ApplyDynamic(const PipelineInfo& info, bool is_dirty) {
|
void PipelineCache::ApplyDynamic(const PipelineInfo& info, bool is_dirty) {
|
||||||
scheduler.Record([is_dirty, current_dynamic = current_info.dynamic,
|
scheduler.Record([is_dirty, current_dynamic = current_info.dynamic,
|
||||||
dynamic = info.dynamic](vk::CommandBuffer cmdbuf) {
|
dynamic = info.dynamic](vk::CommandBuffer cmdbuf) {
|
||||||
|
@ -204,7 +204,7 @@ public:
|
|||||||
void UseFragmentShader(const Pica::Regs& regs);
|
void UseFragmentShader(const Pica::Regs& regs);
|
||||||
|
|
||||||
/// Binds a texture to the specified binding
|
/// Binds a texture to the specified binding
|
||||||
void BindTexture(u32 binding, vk::ImageView image_view);
|
void BindTexture(u32 binding, vk::ImageView image_view, vk::Sampler sampler);
|
||||||
|
|
||||||
/// Binds a storage image to the specified binding
|
/// Binds a storage image to the specified binding
|
||||||
void BindStorageImage(u32 binding, vk::ImageView image_view);
|
void BindStorageImage(u32 binding, vk::ImageView image_view);
|
||||||
@ -215,9 +215,6 @@ public:
|
|||||||
/// Binds a buffer to the specified binding
|
/// Binds a buffer to the specified binding
|
||||||
void BindTexelBuffer(u32 binding, vk::BufferView buffer_view);
|
void BindTexelBuffer(u32 binding, vk::BufferView buffer_view);
|
||||||
|
|
||||||
/// Binds a sampler to the specified binding
|
|
||||||
void BindSampler(u32 binding, vk::Sampler sampler);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Applies dynamic pipeline state to the current command buffer
|
/// Applies dynamic pipeline state to the current command buffer
|
||||||
void ApplyDynamic(const PipelineInfo& info, bool is_dirty);
|
void ApplyDynamic(const PipelineInfo& info, bool is_dirty);
|
||||||
|
@ -129,8 +129,7 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory,
|
|||||||
|
|
||||||
const Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID);
|
const Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID);
|
||||||
for (u32 i = 0; i < 4; i++) {
|
for (u32 i = 0; i < 4; i++) {
|
||||||
pipeline_cache.BindTexture(i, null_surface.ImageView());
|
pipeline_cache.BindTexture(i, null_surface.ImageView(), null_sampler.Handle());
|
||||||
pipeline_cache.BindSampler(i, null_sampler.Handle());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < 7; i++) {
|
for (u32 i = 0; i < 7; i++) {
|
||||||
@ -629,12 +628,10 @@ void RasterizerVulkan::SyncTextureUnits(const Framebuffer& framebuffer) {
|
|||||||
|
|
||||||
auto surface = res_cache.GetTextureCube(config);
|
auto surface = res_cache.GetTextureCube(config);
|
||||||
if (surface) {
|
if (surface) {
|
||||||
pipeline_cache.BindTexture(3, surface->ImageView());
|
pipeline_cache.BindTexture(3, surface->ImageView(), sampler.Handle());
|
||||||
} else {
|
} else {
|
||||||
pipeline_cache.BindTexture(3, null_surface.ImageView());
|
pipeline_cache.BindTexture(3, null_surface.ImageView(), sampler.Handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline_cache.BindSampler(3, sampler.Handle());
|
|
||||||
continue; // Texture unit 0 setup finished. Continue to next unit
|
continue; // Texture unit 0 setup finished. Continue to next unit
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -642,8 +639,6 @@ void RasterizerVulkan::SyncTextureUnits(const Framebuffer& framebuffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline_cache.BindSampler(texture_index, sampler.Handle());
|
|
||||||
|
|
||||||
auto surface = res_cache.GetTextureSurface(texture);
|
auto surface = res_cache.GetTextureSurface(texture);
|
||||||
if (surface) {
|
if (surface) {
|
||||||
if (color_view == surface->ImageView()) {
|
if (color_view == surface->ImageView()) {
|
||||||
@ -658,9 +653,10 @@ void RasterizerVulkan::SyncTextureUnits(const Framebuffer& framebuffer) {
|
|||||||
.extent = {temp.GetScaledWidth(), temp.GetScaledHeight()},
|
.extent = {temp.GetScaledWidth(), temp.GetScaledHeight()},
|
||||||
};
|
};
|
||||||
runtime.CopyTextures(static_cast<Surface&>(*framebuffer.Color()), temp, copy);
|
runtime.CopyTextures(static_cast<Surface&>(*framebuffer.Color()), temp, copy);
|
||||||
pipeline_cache.BindTexture(texture_index, temp.ImageView());
|
pipeline_cache.BindTexture(texture_index, temp.ImageView(), sampler.Handle());
|
||||||
} else {
|
} else {
|
||||||
pipeline_cache.BindTexture(texture_index, surface->ImageView());
|
pipeline_cache.BindTexture(texture_index, surface->ImageView(),
|
||||||
|
sampler.Handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -671,12 +667,13 @@ void RasterizerVulkan::SyncTextureUnits(const Framebuffer& framebuffer) {
|
|||||||
// the geometry in question.
|
// the geometry in question.
|
||||||
// For example: a bug in Pokemon X/Y causes NULL-texture squares to be drawn
|
// For example: a bug in Pokemon X/Y causes NULL-texture squares to be drawn
|
||||||
// on the male character's face, which in the OpenGL default appear black.
|
// on the male character's face, which in the OpenGL default appear black.
|
||||||
pipeline_cache.BindTexture(texture_index, null_surface.ImageView());
|
pipeline_cache.BindTexture(texture_index, null_surface.ImageView(),
|
||||||
|
sampler.Handle());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID);
|
const Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID);
|
||||||
pipeline_cache.BindTexture(texture_index, null_surface.ImageView());
|
pipeline_cache.BindTexture(texture_index, null_surface.ImageView(),
|
||||||
pipeline_cache.BindSampler(texture_index, null_sampler.Handle());
|
null_sampler.Handle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,11 +128,10 @@ void DescriptorPool::Allocate(std::size_t begin, std::size_t end) {
|
|||||||
vk::DescriptorPool& pool = pools.emplace_back();
|
vk::DescriptorPool& pool = pools.emplace_back();
|
||||||
|
|
||||||
// Choose a sane pool size good for most games
|
// Choose a sane pool size good for most games
|
||||||
static constexpr std::array<vk::DescriptorPoolSize, 5> pool_sizes = {{
|
static constexpr std::array<vk::DescriptorPoolSize, 4> pool_sizes = {{
|
||||||
{vk::DescriptorType::eUniformBuffer, 4096},
|
{vk::DescriptorType::eUniformBuffer, 1024},
|
||||||
{vk::DescriptorType::eSampledImage, 4096},
|
{vk::DescriptorType::eCombinedImageSampler, 2048},
|
||||||
{vk::DescriptorType::eSampler, 4096},
|
{vk::DescriptorType::eUniformTexelBuffer, 1024},
|
||||||
{vk::DescriptorType::eUniformTexelBuffer, 2048},
|
|
||||||
{vk::DescriptorType::eStorageImage, 1024},
|
{vk::DescriptorType::eStorageImage, 1024},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
@ -289,13 +289,13 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
|
|||||||
// Only unit 0 respects the texturing type
|
// Only unit 0 respects the texturing type
|
||||||
switch (state.texture0_type) {
|
switch (state.texture0_type) {
|
||||||
case TexturingRegs::TextureConfig::Texture2D:
|
case TexturingRegs::TextureConfig::Texture2D:
|
||||||
return "textureLod(sampler2D(tex0, tex0_sampler), texcoord0, getLod(texcoord0 * "
|
return "textureLod(tex0, texcoord0, getLod(texcoord0 * "
|
||||||
"vec2(textureSize(sampler2D(tex0, tex0_sampler), 0))) + tex_lod_bias[0])";
|
"vec2(textureSize(tex0, 0))) + tex_lod_bias[0])";
|
||||||
case TexturingRegs::TextureConfig::Projection2D:
|
case TexturingRegs::TextureConfig::Projection2D:
|
||||||
// TODO (wwylele): find the exact LOD formula for projection texture
|
// TODO (wwylele): find the exact LOD formula for projection texture
|
||||||
return "textureProj(sampler2D(tex0, tex0_sampler), vec3(texcoord0, texcoord0_w))";
|
return "textureProj(tex0, vec3(texcoord0, texcoord0_w))";
|
||||||
case TexturingRegs::TextureConfig::TextureCube:
|
case TexturingRegs::TextureConfig::TextureCube:
|
||||||
return "texture(samplerCube(tex_cube, tex_cube_sampler), vec3(texcoord0, texcoord0_w))";
|
return "texture(tex_cube, vec3(texcoord0, texcoord0_w))";
|
||||||
case TexturingRegs::TextureConfig::Shadow2D:
|
case TexturingRegs::TextureConfig::Shadow2D:
|
||||||
return "shadowTexture(texcoord0, texcoord0_w)";
|
return "shadowTexture(texcoord0, texcoord0_w)";
|
||||||
case TexturingRegs::TextureConfig::ShadowCube:
|
case TexturingRegs::TextureConfig::ShadowCube:
|
||||||
@ -305,18 +305,18 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
|
|||||||
default:
|
default:
|
||||||
LOG_CRITICAL(HW_GPU, "Unhandled texture type {:x}", state.texture0_type);
|
LOG_CRITICAL(HW_GPU, "Unhandled texture type {:x}", state.texture0_type);
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
return "texture(sampler2D(tex0, tex0_sampler), texcoord0)";
|
return "texture(tex0, texcoord0)";
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
return "textureLod(sampler2D(tex1, tex1_sampler), texcoord1, getLod(texcoord1 * "
|
return "textureLod(tex1, texcoord1, getLod(texcoord1 * "
|
||||||
"vec2(textureSize(sampler2D(tex1, tex1_sampler), 0))) + tex_lod_bias[1])";
|
"vec2(textureSize(tex1, 0))) + tex_lod_bias[1])";
|
||||||
case 2:
|
case 2:
|
||||||
if (state.texture2_use_coord1)
|
if (state.texture2_use_coord1)
|
||||||
return "textureLod(sampler2D(tex2, tex2_sampler), texcoord1, getLod(texcoord1 * "
|
return "textureLod(tex2, texcoord1, getLod(texcoord1 * "
|
||||||
"vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))) + tex_lod_bias[2])";
|
"vec2(textureSize(tex2, 0))) + tex_lod_bias[2])";
|
||||||
else
|
else
|
||||||
return "textureLod(sampler2D(tex2, tex2_sampler), texcoord2, getLod(texcoord2 * "
|
return "textureLod(tex2, texcoord2, getLod(texcoord2 * "
|
||||||
"vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))) + tex_lod_bias[2])";
|
"vec2(textureSize(tex2, 0))) + tex_lod_bias[2])";
|
||||||
case 3:
|
case 3:
|
||||||
if (state.proctex.enable) {
|
if (state.proctex.enable) {
|
||||||
return "ProcTex()";
|
return "ProcTex()";
|
||||||
@ -1217,23 +1217,18 @@ layout(set = 0, binding = 2) uniform samplerBuffer texture_buffer_lut_lf;
|
|||||||
layout(set = 0, binding = 3) uniform samplerBuffer texture_buffer_lut_rg;
|
layout(set = 0, binding = 3) uniform samplerBuffer texture_buffer_lut_rg;
|
||||||
layout(set = 0, binding = 4) uniform samplerBuffer texture_buffer_lut_rgba;
|
layout(set = 0, binding = 4) uniform samplerBuffer texture_buffer_lut_rgba;
|
||||||
|
|
||||||
layout(set = 1, binding = 0) uniform texture2D tex0;
|
layout(set = 1, binding = 0) uniform sampler2D tex0;
|
||||||
layout(set = 1, binding = 1) uniform texture2D tex1;
|
layout(set = 1, binding = 1) uniform sampler2D tex1;
|
||||||
layout(set = 1, binding = 2) uniform texture2D tex2;
|
layout(set = 1, binding = 2) uniform sampler2D tex2;
|
||||||
layout(set = 1, binding = 3) uniform textureCube tex_cube;
|
layout(set = 1, binding = 3) uniform samplerCube tex_cube;
|
||||||
|
|
||||||
layout(set = 2, binding = 0) uniform sampler tex0_sampler;
|
layout(set = 2, binding = 0, r32ui) uniform readonly uimage2D shadow_texture_px;
|
||||||
layout(set = 2, binding = 1) uniform sampler tex1_sampler;
|
layout(set = 2, binding = 1, r32ui) uniform readonly uimage2D shadow_texture_nx;
|
||||||
layout(set = 2, binding = 2) uniform sampler tex2_sampler;
|
layout(set = 2, binding = 2, r32ui) uniform readonly uimage2D shadow_texture_py;
|
||||||
layout(set = 2, binding = 3) uniform sampler tex_cube_sampler;
|
layout(set = 2, binding = 3, r32ui) uniform readonly uimage2D shadow_texture_ny;
|
||||||
|
layout(set = 2, binding = 4, r32ui) uniform readonly uimage2D shadow_texture_pz;
|
||||||
layout(set = 3, binding = 0, r32ui) uniform readonly uimage2D shadow_texture_px;
|
layout(set = 2, binding = 5, r32ui) uniform readonly uimage2D shadow_texture_nz;
|
||||||
layout(set = 3, binding = 1, r32ui) uniform readonly uimage2D shadow_texture_nx;
|
layout(set = 2, binding = 6, r32ui) uniform uimage2D shadow_buffer;
|
||||||
layout(set = 3, binding = 2, r32ui) uniform readonly uimage2D shadow_texture_py;
|
|
||||||
layout(set = 3, binding = 3, r32ui) uniform readonly uimage2D shadow_texture_ny;
|
|
||||||
layout(set = 3, binding = 4, r32ui) uniform readonly uimage2D shadow_texture_pz;
|
|
||||||
layout(set = 3, binding = 5, r32ui) uniform readonly uimage2D shadow_texture_nz;
|
|
||||||
layout(set = 3, binding = 6, r32ui) uniform uimage2D shadow_buffer;
|
|
||||||
)";
|
)";
|
||||||
|
|
||||||
out += UniformBlockDef;
|
out += UniformBlockDef;
|
||||||
|
@ -667,10 +667,8 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
|
|||||||
// This LOD formula is the same as the LOD lower limit defined in OpenGL.
|
// This LOD formula is the same as the LOD lower limit defined in OpenGL.
|
||||||
// f(x, y) >= max{m_u, m_v, m_w}
|
// f(x, y) >= max{m_u, m_v, m_w}
|
||||||
// (See OpenGL 4.6 spec, 8.14.1 - Scale Factor and Level-of-Detail)
|
// (See OpenGL 4.6 spec, 8.14.1 - Scale Factor and Level-of-Detail)
|
||||||
const auto SampleLod = [this, texture_unit](Id tex_id, Id tex_sampler_id, Id texcoord_id) {
|
const auto SampleLod = [this, texture_unit](Id tex_id, Id texcoord_id) {
|
||||||
const Id tex{OpLoad(image2d_id, tex_id)};
|
const Id sampled_image{OpLoad(TypeSampledImage(image2d_id), tex_id)};
|
||||||
const Id tex_sampler{OpLoad(sampler_id, tex_sampler_id)};
|
|
||||||
const Id sampled_image{OpSampledImage(TypeSampledImage(image2d_id), tex, tex_sampler)};
|
|
||||||
const Id tex_image{OpImage(image2d_id, sampled_image)};
|
const Id tex_image{OpImage(image2d_id, sampled_image)};
|
||||||
const Id tex_size{OpImageQuerySizeLod(ivec_ids.Get(2), tex_image, ConstS32(0))};
|
const Id tex_size{OpImageQuerySizeLod(ivec_ids.Get(2), tex_image, ConstS32(0))};
|
||||||
const Id texcoord{OpLoad(vec_ids.Get(2), texcoord_id)};
|
const Id texcoord{OpLoad(vec_ids.Get(2), texcoord_id)};
|
||||||
@ -687,11 +685,9 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
|
|||||||
spv::ImageOperandsMask::Lod, biased_lod);
|
spv::ImageOperandsMask::Lod, biased_lod);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto Sample = [this](Id tex_id, Id tex_sampler_id, bool projection) {
|
const auto Sample = [this](Id tex_id, bool projection) {
|
||||||
const Id image_type = tex_id.value == tex_cube_id.value ? image_cube_id : image2d_id;
|
const Id image_type = tex_id.value == tex_cube_id.value ? image_cube_id : image2d_id;
|
||||||
const Id tex{OpLoad(image_type, tex_id)};
|
const Id sampled_image{OpLoad(TypeSampledImage(image_type), tex_id)};
|
||||||
const Id tex_sampler{OpLoad(sampler_id, tex_sampler_id)};
|
|
||||||
const Id sampled_image{OpSampledImage(TypeSampledImage(image_type), tex, tex_sampler)};
|
|
||||||
const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)};
|
const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)};
|
||||||
const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)};
|
const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)};
|
||||||
const Id coord{OpCompositeConstruct(vec_ids.Get(3),
|
const Id coord{OpCompositeConstruct(vec_ids.Get(3),
|
||||||
@ -709,11 +705,11 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
|
|||||||
// Only unit 0 respects the texturing type
|
// Only unit 0 respects the texturing type
|
||||||
switch (state.texture0_type) {
|
switch (state.texture0_type) {
|
||||||
case Pica::TexturingRegs::TextureConfig::Texture2D:
|
case Pica::TexturingRegs::TextureConfig::Texture2D:
|
||||||
return SampleLod(tex0_id, tex0_sampler_id, texcoord0_id);
|
return SampleLod(tex0_id, texcoord0_id);
|
||||||
case Pica::TexturingRegs::TextureConfig::Projection2D:
|
case Pica::TexturingRegs::TextureConfig::Projection2D:
|
||||||
return Sample(tex0_id, tex0_sampler_id, true);
|
return Sample(tex0_id, true);
|
||||||
case Pica::TexturingRegs::TextureConfig::TextureCube:
|
case Pica::TexturingRegs::TextureConfig::TextureCube:
|
||||||
return Sample(tex_cube_id, tex_cube_sampler_id, false);
|
return Sample(tex_cube_id, false);
|
||||||
case Pica::TexturingRegs::TextureConfig::Shadow2D:
|
case Pica::TexturingRegs::TextureConfig::Shadow2D:
|
||||||
return SampleShadow();
|
return SampleShadow();
|
||||||
// case Pica::TexturingRegs::TextureConfig::ShadowCube:
|
// case Pica::TexturingRegs::TextureConfig::ShadowCube:
|
||||||
@ -726,12 +722,12 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
|
|||||||
return zero_vec;
|
return zero_vec;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
return SampleLod(tex1_id, tex1_sampler_id, texcoord1_id);
|
return SampleLod(tex1_id, texcoord1_id);
|
||||||
case 2:
|
case 2:
|
||||||
if (state.texture2_use_coord1) {
|
if (state.texture2_use_coord1) {
|
||||||
return SampleLod(tex2_id, tex2_sampler_id, texcoord1_id);
|
return SampleLod(tex2_id, texcoord1_id);
|
||||||
} else {
|
} else {
|
||||||
return SampleLod(tex2_id, tex2_sampler_id, texcoord2_id);
|
return SampleLod(tex2_id, texcoord2_id);
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
if (state.proctex.enable) {
|
if (state.proctex.enable) {
|
||||||
@ -1445,15 +1441,11 @@ void FragmentModule::DefineInterface() {
|
|||||||
texture_buffer_lut_lf_id = DefineUniformConst(TypeSampledImage(image_buffer_id), 0, 2);
|
texture_buffer_lut_lf_id = DefineUniformConst(TypeSampledImage(image_buffer_id), 0, 2);
|
||||||
texture_buffer_lut_rg_id = DefineUniformConst(TypeSampledImage(image_buffer_id), 0, 3);
|
texture_buffer_lut_rg_id = DefineUniformConst(TypeSampledImage(image_buffer_id), 0, 3);
|
||||||
texture_buffer_lut_rgba_id = DefineUniformConst(TypeSampledImage(image_buffer_id), 0, 4);
|
texture_buffer_lut_rgba_id = DefineUniformConst(TypeSampledImage(image_buffer_id), 0, 4);
|
||||||
tex0_id = DefineUniformConst(image2d_id, 1, 0);
|
tex0_id = DefineUniformConst(TypeSampledImage(image2d_id), 1, 0);
|
||||||
tex1_id = DefineUniformConst(image2d_id, 1, 1);
|
tex1_id = DefineUniformConst(TypeSampledImage(image2d_id), 1, 1);
|
||||||
tex2_id = DefineUniformConst(image2d_id, 1, 2);
|
tex2_id = DefineUniformConst(TypeSampledImage(image2d_id), 1, 2);
|
||||||
tex_cube_id = DefineUniformConst(image_cube_id, 1, 3);
|
tex_cube_id = DefineUniformConst(TypeSampledImage(image_cube_id), 1, 3);
|
||||||
tex0_sampler_id = DefineUniformConst(sampler_id, 2, 0);
|
shadow_texture_px_id = DefineUniformConst(image_r32_id, 2, 0, true);
|
||||||
tex1_sampler_id = DefineUniformConst(sampler_id, 2, 1);
|
|
||||||
tex2_sampler_id = DefineUniformConst(sampler_id, 2, 2);
|
|
||||||
tex_cube_sampler_id = DefineUniformConst(sampler_id, 2, 3);
|
|
||||||
shadow_texture_px_id = DefineUniformConst(image_r32_id, 3, 0, true);
|
|
||||||
|
|
||||||
// Define built-ins
|
// Define built-ins
|
||||||
gl_frag_coord_id = DefineVar(vec_ids.Get(4), spv::StorageClass::Input);
|
gl_frag_coord_id = DefineVar(vec_ids.Get(4), spv::StorageClass::Input);
|
||||||
|
@ -240,10 +240,6 @@ private:
|
|||||||
Id tex1_id{};
|
Id tex1_id{};
|
||||||
Id tex2_id{};
|
Id tex2_id{};
|
||||||
Id tex_cube_id{};
|
Id tex_cube_id{};
|
||||||
Id tex0_sampler_id{};
|
|
||||||
Id tex1_sampler_id{};
|
|
||||||
Id tex2_sampler_id{};
|
|
||||||
Id tex_cube_sampler_id{};
|
|
||||||
Id texture_buffer_lut_lf_id{};
|
Id texture_buffer_lut_lf_id{};
|
||||||
Id texture_buffer_lut_rg_id{};
|
Id texture_buffer_lut_rg_id{};
|
||||||
Id texture_buffer_lut_rgba_id{};
|
Id texture_buffer_lut_rgba_id{};
|
||||||
|
@ -730,7 +730,6 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextureRuntime::GenerateMipmaps(Surface& surface) {
|
void TextureRuntime::GenerateMipmaps(Surface& surface) {
|
||||||
return;
|
|
||||||
if (surface.custom_format != VideoCore::CustomPixelFormat::RGBA8) {
|
if (surface.custom_format != VideoCore::CustomPixelFormat::RGBA8) {
|
||||||
LOG_ERROR(Render_Vulkan, "Generating mipmaps for compressed formats unsupported!");
|
LOG_ERROR(Render_Vulkan, "Generating mipmaps for compressed formats unsupported!");
|
||||||
return;
|
return;
|
||||||
@ -1338,8 +1337,8 @@ Sampler::Sampler(TextureRuntime& runtime, VideoCore::SamplerParams params)
|
|||||||
.maxAnisotropy = properties.limits.maxSamplerAnisotropy,
|
.maxAnisotropy = properties.limits.maxSamplerAnisotropy,
|
||||||
.compareEnable = false,
|
.compareEnable = false,
|
||||||
.compareOp = vk::CompareOp::eAlways,
|
.compareOp = vk::CompareOp::eAlways,
|
||||||
.minLod = 0.f * lod_min,
|
.minLod = lod_min,
|
||||||
.maxLod = 0.f * lod_max,
|
.maxLod = lod_max,
|
||||||
.borderColor =
|
.borderColor =
|
||||||
use_border_color ? vk::BorderColor::eFloatCustomEXT : vk::BorderColor::eIntOpaqueBlack,
|
use_border_color ? vk::BorderColor::eFloatCustomEXT : vk::BorderColor::eIntOpaqueBlack,
|
||||||
.unnormalizedCoordinates = false,
|
.unnormalizedCoordinates = false,
|
||||||
|
Reference in New Issue
Block a user