From 75d9236520901e5eb64eaccd78621fc020fad185 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sat, 15 Nov 2025 19:18:00 -0400 Subject: [PATCH] [vk, pipeline_cache, texture_cache, qcom] Resolving textures and pipeline usage for QCOM --- .../renderer_vulkan/vk_pipeline_cache.cpp | 23 ++++++++++++++++++- .../renderer_vulkan/vk_texture_cache.cpp | 14 +++++++---- src/video_core/vulkan_common/vulkan_device.h | 6 +++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 15805f8480..ed494c243c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -691,7 +691,17 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)}; ConvertLegacyToGeneric(program, runtime_info); - const std::vector code{EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output)}; + + // Adreno don't support subgroup operations in vertex stages + // Disable subgroup features for vertex shaders if not supported by the device + Shader::Profile stage_profile = profile; + if (program.stage == Shader::Stage::VertexA || program.stage == Shader::Stage::VertexB) { + if (!device.IsSubgroupSupportedForStage(VK_SHADER_STAGE_VERTEX_BIT)) { + stage_profile.support_vote = false; + } + } + + const std::vector code{EmitSPIRV(stage_profile, runtime_info, program, binding, this->optimize_spirv_output)}; device.SaveShader(code); modules[stage_index] = BuildShader(device, code); if (device.HasDebuggingToolAttached()) { @@ -785,6 +795,17 @@ std::unique_ptr PipelineCache::CreateComputePipeline( } auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; + + // Adreno have lower shared memory limits (32KB) + // Clamp shared memory usage to device maximum to avoid validation errors + const u32 max_shared_memory = device.GetMaxComputeSharedMemorySize(); + if (program.shared_memory_size > max_shared_memory) { + LOG_WARNING(Render_Vulkan, + "Compute shader 0x{:016x} requests {}KB shared memory but device max is {}KB - clamping", + key.unique_hash, program.shared_memory_size / 1024, max_shared_memory / 1024); + program.shared_memory_size = max_shared_memory; + } + const std::vector code{EmitSPIRV(profile, program, this->optimize_spirv_output)}; device.SaveShader(code); vk::ShaderModule spv_module{BuildShader(device, code)}; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index ba790f6555..edd2c7b4a7 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -2130,6 +2130,12 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI .pNext = nullptr, .usage = ImageUsageFlags(format_info, format), }; + + // Vulkan spec: STORAGE_IMAGE and INPUT_ATTACHMENT descriptors MUST use identity swizzle + // Using non-identity swizzle causes validation error and undefined behavior + const bool requires_identity_swizzle = + (image_view_usage.usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) != 0; + const VkImageViewCreateInfo create_info{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = &image_view_usage, @@ -2138,10 +2144,10 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI .viewType = VkImageViewType{}, .format = format_info.format, .components{ - .r = ComponentSwizzle(swizzle[0]), - .g = ComponentSwizzle(swizzle[1]), - .b = ComponentSwizzle(swizzle[2]), - .a = ComponentSwizzle(swizzle[3]), + .r = requires_identity_swizzle ? VK_COMPONENT_SWIZZLE_IDENTITY : ComponentSwizzle(swizzle[0]), + .g = requires_identity_swizzle ? VK_COMPONENT_SWIZZLE_IDENTITY : ComponentSwizzle(swizzle[1]), + .b = requires_identity_swizzle ? VK_COMPONENT_SWIZZLE_IDENTITY : ComponentSwizzle(swizzle[2]), + .a = requires_identity_swizzle ? VK_COMPONENT_SWIZZLE_IDENTITY : ComponentSwizzle(swizzle[3]), }, .subresourceRange = MakeSubresourceRange(aspect_mask, info.range), }; diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index ba516efd9c..07f4446197 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -382,6 +382,12 @@ public: return properties.subgroup_properties.supportedOperations & feature; } + /// Returns true if subgroup operations are supported in the specified shader stage. + /// Mobile GPUs (Qualcomm Adreno) often only support subgroups in fragment/compute stages. + bool IsSubgroupSupportedForStage(VkShaderStageFlagBits stage) const { + return properties.subgroup_properties.supportedStages & stage; + } + /// Returns the maximum number of push descriptors. u32 MaxPushDescriptors() const { return properties.push_descriptor.maxPushDescriptors;