renderer_vulkan: Set up and configure VK_KHR_portability_subset extension according to spec. (#12)
* renderer_vulkan: Set up and configure VK_KHR_portability_subset extension according to spec. * renderer_vulkan: Move mipmap LOD bias to shaders for compatibility.
This commit is contained in:
@@ -643,6 +643,18 @@ void RasterizerAccelerated::NotifyPicaRegisterChanged(u32 id) {
|
||||
uniform_block_data.lighting_lut_dirty_any = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Texture LOD biases
|
||||
case PICA_REG_INDEX(texturing.texture0.lod.bias):
|
||||
SyncTextureLodBias(0);
|
||||
break;
|
||||
case PICA_REG_INDEX(texturing.texture1.lod.bias):
|
||||
SyncTextureLodBias(1);
|
||||
break;
|
||||
case PICA_REG_INDEX(texturing.texture2.lod.bias):
|
||||
SyncTextureLodBias(2);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Forward registers that map to fixed function API features to the video backend
|
||||
NotifyFixedFunctionPicaRegisterChanged(id);
|
||||
@@ -840,4 +852,13 @@ void RasterizerAccelerated::SyncShadowTextureBias() {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerAccelerated::SyncTextureLodBias(int tex_index) {
|
||||
const auto pica_textures = Pica::g_state.regs.texturing.GetTextures();
|
||||
const float bias = pica_textures[tex_index].config.lod.bias / 256.0f;
|
||||
if (bias != uniform_block_data.data.tex_lod_bias[tex_index]) {
|
||||
uniform_block_data.data.tex_lod_bias[tex_index] = bias;
|
||||
uniform_block_data.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace VideoCore
|
||||
|
@@ -85,6 +85,9 @@ protected:
|
||||
/// Syncs the shadow texture bias to match the PICA register
|
||||
void SyncShadowTextureBias();
|
||||
|
||||
/// Syncs the texture LOD bias to match the PICA register
|
||||
void SyncTextureLodBias(int tex_index);
|
||||
|
||||
protected:
|
||||
/// Structure that keeps tracks of the uniform state
|
||||
struct UniformBlockData {
|
||||
|
@@ -176,6 +176,10 @@ void RasterizerOpenGL::SyncEntireState() {
|
||||
SyncProcTexBias();
|
||||
SyncShadowBias();
|
||||
SyncShadowTextureBias();
|
||||
|
||||
for (unsigned tex_index = 0; tex_index < 3; tex_index++) {
|
||||
SyncTextureLodBias(tex_index);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr std::array<GLenum, 4> vs_attrib_types{
|
||||
@@ -991,7 +995,6 @@ void RasterizerOpenGL::SamplerInfo::Create() {
|
||||
wrap_s = wrap_t = TextureConfig::Repeat;
|
||||
border_color = 0;
|
||||
lod_min = lod_max = 0;
|
||||
lod_bias = 0;
|
||||
|
||||
// default is 1000 and -1000
|
||||
// Other attributes have correct defaults
|
||||
@@ -1053,11 +1056,6 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(
|
||||
lod_max = config.lod.max_level;
|
||||
glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, static_cast<float>(lod_max));
|
||||
}
|
||||
|
||||
if (!GLES && lod_bias != config.lod.bias) {
|
||||
lod_bias = config.lod.bias;
|
||||
glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, lod_bias / 256.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SetShader() {
|
||||
|
@@ -66,7 +66,6 @@ private:
|
||||
u32 border_color;
|
||||
u32 lod_min;
|
||||
u32 lod_max;
|
||||
s32 lod_bias;
|
||||
|
||||
// TODO(wwylele): remove this once mipmap for cube is implemented
|
||||
bool supress_mipmap_for_cube = false;
|
||||
|
@@ -68,6 +68,7 @@ layout (std140) uniform shader_data {
|
||||
vec4 const_color[NUM_TEV_STAGES];
|
||||
vec4 tev_combiner_buffer_color;
|
||||
vec4 clip_coef;
|
||||
vec3 tex_lod_bias;
|
||||
};
|
||||
)";
|
||||
|
||||
@@ -307,7 +308,7 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
|
||||
// Only unit 0 respects the texturing type
|
||||
switch (state.texture0_type) {
|
||||
case TexturingRegs::TextureConfig::Texture2D:
|
||||
return "textureLod(tex0, texcoord0, getLod(texcoord0 * vec2(textureSize(tex0, 0))))";
|
||||
return "textureLod(tex0, texcoord0, getLod(texcoord0 * vec2(textureSize(tex0, 0))) + tex_lod_bias[0])";
|
||||
case TexturingRegs::TextureConfig::Projection2D:
|
||||
// TODO (wwylele): find the exact LOD formula for projection texture
|
||||
return "textureProj(tex0, vec3(texcoord0, texcoord0_w))";
|
||||
@@ -325,12 +326,12 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
|
||||
return "texture(tex0, texcoord0)";
|
||||
}
|
||||
case 1:
|
||||
return "textureLod(tex1, texcoord1, getLod(texcoord1 * vec2(textureSize(tex1, 0))))";
|
||||
return "textureLod(tex1, texcoord1, getLod(texcoord1 * vec2(textureSize(tex1, 0))) + tex_lod_bias[1])";
|
||||
case 2:
|
||||
if (state.texture2_use_coord1)
|
||||
return "textureLod(tex2, texcoord1, getLod(texcoord1 * vec2(textureSize(tex2, 0))))";
|
||||
return "textureLod(tex2, texcoord1, getLod(texcoord1 * vec2(textureSize(tex2, 0))) + tex_lod_bias[2])";
|
||||
else
|
||||
return "textureLod(tex2, texcoord2, getLod(texcoord2 * vec2(textureSize(tex2, 0))))";
|
||||
return "textureLod(tex2, texcoord2, getLod(texcoord2 * vec2(textureSize(tex2, 0))) + tex_lod_bias[2])";
|
||||
case 3:
|
||||
if (state.proctex.enable) {
|
||||
return "ProcTex()";
|
||||
|
@@ -356,6 +356,7 @@ void Instance::CreateFormatTable() {
|
||||
bool Instance::CreateDevice() {
|
||||
const vk::StructureChain feature_chain =
|
||||
physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
|
||||
vk::PhysicalDevicePortabilitySubsetFeaturesKHR,
|
||||
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT,
|
||||
vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR,
|
||||
vk::PhysicalDeviceCustomBorderColorFeaturesEXT,
|
||||
@@ -393,6 +394,8 @@ bool Instance::CreateDevice() {
|
||||
};
|
||||
|
||||
AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
// According to the Vulkan spec, VK_KHR_portability_subset must be added if supported.
|
||||
bool portability_subset = AddExtension(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
|
||||
timeline_semaphores = AddExtension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME);
|
||||
extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||
push_descriptors = AddExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||
@@ -473,12 +476,28 @@ bool Instance::CreateDevice() {
|
||||
.shaderClipDistance = features.shaderClipDistance,
|
||||
},
|
||||
},
|
||||
feature_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>(),
|
||||
feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>(),
|
||||
feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(),
|
||||
feature_chain.get<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>(),
|
||||
feature_chain.get<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>(),
|
||||
};
|
||||
|
||||
if (portability_subset) {
|
||||
const vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features =
|
||||
feature_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
|
||||
triangle_fan_supported = portability_features.triangleFans;
|
||||
|
||||
const vk::StructureChain portability_properties_chain =
|
||||
physical_device.getProperties2<vk::PhysicalDeviceProperties2,
|
||||
vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
|
||||
const vk::PhysicalDevicePortabilitySubsetPropertiesKHR portability_properties =
|
||||
portability_properties_chain.get<vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
|
||||
min_vertex_stride_alignment = portability_properties.minVertexInputBindingStrideAlignment;
|
||||
} else {
|
||||
device_chain.unlink<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
|
||||
}
|
||||
|
||||
if (!index_type_uint8) {
|
||||
device_chain.unlink<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>();
|
||||
}
|
||||
@@ -491,22 +510,6 @@ bool Instance::CreateDevice() {
|
||||
device_chain.unlink<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>();
|
||||
}
|
||||
|
||||
#if __APPLE__
|
||||
const vk::StructureChain portability_features_chain =
|
||||
physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
|
||||
vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
|
||||
const vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features =
|
||||
portability_features_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
|
||||
triangle_fan_supported = portability_features.triangleFans;
|
||||
|
||||
const vk::StructureChain portability_properties_chain =
|
||||
physical_device.getProperties2<vk::PhysicalDeviceProperties2,
|
||||
vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
|
||||
const vk::PhysicalDevicePortabilitySubsetPropertiesKHR portability_properties =
|
||||
portability_properties_chain.get<vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
|
||||
min_vertex_stride_alignment = portability_properties.minVertexInputBindingStrideAlignment;
|
||||
#endif
|
||||
|
||||
try {
|
||||
device = physical_device.createDevice(device_chain.get());
|
||||
} catch (vk::ExtensionNotPresentError& err) {
|
||||
|
@@ -184,6 +184,10 @@ void RasterizerVulkan::SyncEntireState() {
|
||||
SyncProcTexBias();
|
||||
SyncShadowBias();
|
||||
SyncShadowTextureBias();
|
||||
|
||||
for (unsigned tex_index = 0; tex_index < 3; tex_index++) {
|
||||
SyncTextureLodBias(tex_index);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SyncFixedState() {
|
||||
@@ -593,8 +597,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
.wrap_t = config.wrap_t,
|
||||
.border_color = config.border_color.raw,
|
||||
.lod_min = skip_mipmap ? 0.f : static_cast<float>(config.lod.min_level),
|
||||
.lod_max = skip_mipmap ? 0.f : static_cast<float>(config.lod.max_level),
|
||||
.lod_bias = static_cast<float>(config.lod.bias),
|
||||
.lod_max = skip_mipmap ? 0.f : static_cast<float>(config.lod.max_level)
|
||||
};
|
||||
|
||||
// Search the cache and bind the appropriate sampler
|
||||
@@ -1141,7 +1144,7 @@ vk::Sampler RasterizerVulkan::CreateSampler(const SamplerInfo& info) {
|
||||
.mipmapMode = PicaToVK::TextureMipFilterMode(info.mip_filter),
|
||||
.addressModeU = PicaToVK::WrapMode(info.wrap_s),
|
||||
.addressModeV = PicaToVK::WrapMode(info.wrap_t),
|
||||
.mipLodBias = info.lod_bias / 256.0f,
|
||||
.mipLodBias = 0,
|
||||
.anisotropyEnable = instance.IsAnisotropicFilteringSupported(),
|
||||
.maxAnisotropy = properties.limits.maxSamplerAnisotropy,
|
||||
.compareEnable = false,
|
||||
|
@@ -34,7 +34,6 @@ struct SamplerInfo {
|
||||
u32 border_color = 0;
|
||||
float lod_min = 0;
|
||||
float lod_max = 0;
|
||||
float lod_bias = 0;
|
||||
|
||||
// TODO(wwylele): remove this once mipmap for cube is implemented
|
||||
bool supress_mipmap_for_cube = false;
|
||||
|
@@ -69,6 +69,7 @@ layout (set = 0, binding = 1, std140) uniform shader_data {
|
||||
vec4 const_color[NUM_TEV_STAGES];
|
||||
vec4 tev_combiner_buffer_color;
|
||||
vec4 clip_coef;
|
||||
vec3 tex_lod_bias;
|
||||
};
|
||||
)";
|
||||
|
||||
@@ -325,7 +326,7 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
|
||||
switch (state.texture0_type) {
|
||||
case TexturingRegs::TextureConfig::Texture2D:
|
||||
return "textureLod(sampler2D(tex0, tex0_sampler), texcoord0, getLod(texcoord0 * "
|
||||
"vec2(textureSize(sampler2D(tex0, tex0_sampler), 0))))";
|
||||
"vec2(textureSize(sampler2D(tex0, tex0_sampler), 0))) + tex_lod_bias[0])";
|
||||
case TexturingRegs::TextureConfig::Projection2D:
|
||||
// TODO (wwylele): find the exact LOD formula for projection texture
|
||||
return "textureProj(sampler2D(tex0, tex0_sampler), vec3(texcoord0, texcoord0_w))";
|
||||
@@ -344,14 +345,14 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
|
||||
}
|
||||
case 1:
|
||||
return "textureLod(sampler2D(tex1, tex1_sampler), texcoord1, getLod(texcoord1 * "
|
||||
"vec2(textureSize(sampler2D(tex1, tex1_sampler), 0))))";
|
||||
"vec2(textureSize(sampler2D(tex1, tex1_sampler), 0))) + tex_lod_bias[1])";
|
||||
case 2:
|
||||
if (state.texture2_use_coord1)
|
||||
return "textureLod(sampler2D(tex2, tex2_sampler), texcoord1, getLod(texcoord1 * "
|
||||
"vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))))";
|
||||
"vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))) + tex_lod_bias[2])";
|
||||
else
|
||||
return "textureLod(sampler2D(tex2, tex2_sampler), texcoord2, getLod(texcoord2 * "
|
||||
"vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))))";
|
||||
"vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))) + tex_lod_bias[2])";
|
||||
case 3:
|
||||
if (state.proctex.enable) {
|
||||
return "ProcTex()";
|
||||
|
@@ -610,7 +610,7 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
|
||||
// This LOD formula is the same as the LOD lower limit defined in OpenGL.
|
||||
// f(x, y) >= max{m_u, m_v, m_w}
|
||||
// (See OpenGL 4.6 spec, 8.14.1 - Scale Factor and Level-of-Detail)
|
||||
const auto SampleLod = [this](Id tex_id, Id tex_sampler_id, Id texcoord_id) {
|
||||
const auto SampleLod = [this, texture_unit](Id tex_id, Id tex_sampler_id, Id texcoord_id) {
|
||||
const Id tex{OpLoad(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)};
|
||||
@@ -624,8 +624,10 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
|
||||
const Id dx_dy_max{
|
||||
OpFMax(f32_id, OpCompositeExtract(f32_id, d, 0), OpCompositeExtract(f32_id, d, 1))};
|
||||
const Id lod{OpLog2(f32_id, dx_dy_max)};
|
||||
const Id lod_bias{GetShaderDataMember(f32_id, ConstS32(29), ConstU32(texture_unit))};
|
||||
const Id biased_lod{OpFAdd(f32_id, lod, lod_bias)};
|
||||
return OpImageSampleExplicitLod(vec_ids.Get(4), sampled_image, texcoord,
|
||||
spv::ImageOperandsMask::Lod, lod);
|
||||
spv::ImageOperandsMask::Lod, biased_lod);
|
||||
};
|
||||
|
||||
const auto Sample = [this](Id tex_id, Id tex_sampler_id, bool projection) {
|
||||
@@ -1342,12 +1344,12 @@ void FragmentModule::DefineUniformStructs() {
|
||||
i32_id, i32_id, f32_id, f32_id, f32_id, f32_id, i32_id, i32_id, i32_id, i32_id, i32_id,
|
||||
i32_id, i32_id, i32_id, i32_id, i32_id, f32_id, i32_id, u32_id, lighting_lut_array_id,
|
||||
vec_ids.Get(3), vec_ids.Get(2), vec_ids.Get(2), vec_ids.Get(2), vec_ids.Get(3),
|
||||
light_src_array_id, const_color_array_id, vec_ids.Get(4), vec_ids.Get(4))};
|
||||
light_src_array_id, const_color_array_id, vec_ids.Get(4), vec_ids.Get(4), vec_ids.Get(3))};
|
||||
|
||||
constexpr std::array light_src_offsets{0u, 16u, 32u, 48u, 64u, 80u, 92u, 96u};
|
||||
constexpr std::array shader_data_offsets{
|
||||
0u, 4u, 8u, 12u, 16u, 20u, 24u, 28u, 32u, 36u, 40u, 44u, 48u, 52u, 56u,
|
||||
60u, 64u, 68u, 72u, 80u, 176u, 192u, 200u, 208u, 224u, 240u, 1136u, 1232u, 1248u};
|
||||
60u, 64u, 68u, 72u, 80u, 176u, 192u, 200u, 208u, 224u, 240u, 1136u, 1232u, 1248u, 1264u};
|
||||
|
||||
Decorate(lighting_lut_array_id, spv::Decoration::ArrayStride, 16u);
|
||||
Decorate(light_src_array_id, spv::Decoration::ArrayStride, 112u);
|
||||
|
@@ -64,9 +64,10 @@ struct UniformData {
|
||||
alignas(16) Common::Vec4f const_color[6]; // A vec4 color for each of the six tev stages
|
||||
alignas(16) Common::Vec4f tev_combiner_buffer_color;
|
||||
alignas(16) Common::Vec4f clip_coef;
|
||||
alignas(16) Common::Vec3f tex_lod_bias;
|
||||
};
|
||||
|
||||
static_assert(sizeof(UniformData) == 0x4F0,
|
||||
static_assert(sizeof(UniformData) == 0x500,
|
||||
"The size of the UniformData does not match the structure in the shader");
|
||||
static_assert(sizeof(UniformData) < 16384,
|
||||
"UniformData structure must be less than 16kb as per the OpenGL spec");
|
||||
|
Reference in New Issue
Block a user