Browse Source

Added most missing bindless OPCodes

Added debug logging for later
Restored earlier code that was more consistent
pull/3300/head
Forrest Keller 2 months ago
parent
commit
e9ae136f8f
  1. 239
      src/shader_recompiler/ir_opt/texture_pass.cpp
  2. 33
      src/video_core/renderer_vulkan/pipeline_helper.h
  3. 9
      src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp

239
src/shader_recompiler/ir_opt/texture_pass.cpp

@ -244,9 +244,179 @@ std::optional<u32> TryGetConstant(IR::Value& value, Environment& env) {
}
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env) {
switch (inst->GetOpcode()) {
const auto opcode = inst->GetOpcode();
switch (opcode) {
default:
LOG_DEBUG(Render_Vulkan, "TryGetConstBuffer: Unhandled opcode {}", static_cast<int>(opcode));
return std::nullopt;
case IR::Opcode::BitCastU16F16:
case IR::Opcode::BitCastF16U16:
case IR::Opcode::BitCastU32F32:
case IR::Opcode::BitCastF32U32:
case IR::Opcode::BitCastU64F64:
case IR::Opcode::BitCastF64U64:
return Track(inst->Arg(0), env);
case IR::Opcode::ConvertU32U64:
case IR::Opcode::ConvertU64U32:
return Track(inst->Arg(0), env);
case IR::Opcode::SelectU1:
case IR::Opcode::SelectU8:
case IR::Opcode::SelectU16:
case IR::Opcode::SelectU32:
case IR::Opcode::SelectU64:
case IR::Opcode::SelectF16:
case IR::Opcode::SelectF32:
case IR::Opcode::SelectF64: {
if (auto result = Track(inst->Arg(1), env)) {
return result;
}
if (auto result = Track(inst->Arg(2), env)) {
return result;
}
LOG_DEBUG(Render_Vulkan, "Select operation failed both branches");
return std::nullopt;
}
case IR::Opcode::IAdd32: {
const IR::Value op1{inst->Arg(0)};
const IR::Value op2{inst->Arg(1)};
if (op2.IsImmediate()) {
if (auto res = Track(op1, env)) {
res->offset += op2.U32();
return res;
}
}
if (op1.IsImmediate()) {
if (auto res = Track(op2, env)) {
res->offset += op1.U32();
return res;
}
}
if (auto result = Track(op1, env)) {
return result;
}
if (auto result = Track(op2, env)) {
return result;
}
return std::nullopt;
}
case IR::Opcode::IAdd64: {
const IR::Value op1{inst->Arg(0)};
const IR::Value op2{inst->Arg(1)};
if (op2.IsImmediate()) {
if (auto res = Track(op1, env)) {
res->offset += static_cast<u32>(op2.U64());
return res;
}
}
if (op1.IsImmediate()) {
if (auto res = Track(op2, env)) {
res->offset += static_cast<u32>(op1.U64());
return res;
}
}
if (auto result = Track(op1, env)) {
return result;
}
if (auto result = Track(op2, env)) {
return result;
}
return std::nullopt;
}
case IR::Opcode::ShiftRightLogical32: {
const IR::Value base{inst->Arg(0)};
const IR::Value shift{inst->Arg(1)};
if (auto res = Track(base, env)) {
if (shift.IsImmediate()) {
res->offset += (shift.U32() / 8);
}
return res;
}
return std::nullopt;
}
case IR::Opcode::ShiftRightLogical64: {
const IR::Value base{inst->Arg(0)};
const IR::Value shift{inst->Arg(1)};
if (auto res = Track(base, env)) {
if (shift.IsImmediate()) {
res->offset += (shift.U32() / 8);
}
return res;
}
return std::nullopt;
}
case IR::Opcode::BitFieldUExtract: {
const IR::Value base{inst->Arg(0)};
const IR::Value offset{inst->Arg(1)};
const IR::Value count{inst->Arg(2)};
if (auto res = Track(base, env)) {
if (offset.IsImmediate()) {
res->offset += (offset.U32() / 8);
res->shift_left = offset.U32() % 32;
}
return res;
}
return std::nullopt;
}
case IR::Opcode::PackUint2x32: {
const IR::Value composite{inst->Arg(0)};
if (composite.IsImmediate()) {
return std::nullopt;
}
IR::Inst* const composite_inst{composite.InstRecursive()};
if (composite_inst->GetOpcode() == IR::Opcode::CompositeConstructU32x2) {
std::optional lhs{Track(composite_inst->Arg(0), env)};
std::optional rhs{Track(composite_inst->Arg(1), env)};
if (!lhs || !rhs) {
return std::nullopt;
}
if (lhs->has_secondary || rhs->has_secondary) {
return std::nullopt;
}
if (lhs->count > 1 || rhs->count > 1) {
return std::nullopt;
}
return ConstBufferAddr{
.index = lhs->index,
.offset = lhs->offset,
.shift_left = lhs->shift_left,
.secondary_index = rhs->index,
.secondary_offset = rhs->offset,
.secondary_shift_left = rhs->shift_left,
.dynamic_offset = {},
.count = 1,
.has_secondary = true,
};
}
return std::nullopt;
}
case IR::Opcode::UnpackUint2x32:
return Track(inst->Arg(0), env);
case IR::Opcode::CompositeConstructU32x2:
if (auto result = Track(inst->Arg(0), env)) {
return result;
}
if (auto result = Track(inst->Arg(1), env)) {
return result;
}
return std::nullopt;
case IR::Opcode::CompositeExtractU32x2: {
const IR::Value composite{inst->Arg(0)};
const IR::Value index_val{inst->Arg(1)};
if (auto res = Track(composite, env)) {
if (index_val.IsImmediate()) {
res->offset += index_val.U32() * 4;
}
return res;
}
return std::nullopt;
}
case IR::Opcode::BitwiseOr32: {
std::optional lhs{TrackCached(inst->Arg(0), env)};
std::optional rhs{TrackCached(inst->Arg(1), env)};
@ -259,9 +429,23 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
if (lhs->count > 1 || rhs->count > 1) {
return std::nullopt;
}
if (lhs->shift_left > 0 || lhs->index > rhs->index || lhs->offset > rhs->offset) {
bool lhs_is_low = true;
if (lhs->index == rhs->index) {
if (lhs->offset > rhs->offset) {
lhs_is_low = false;
} else if (lhs->offset == rhs->offset) {
if (lhs->shift_left > rhs->shift_left) {
lhs_is_low = false;
}
}
}
if (!lhs_is_low) {
std::swap(lhs, rhs);
}
return ConstBufferAddr{
.index = lhs->index,
.offset = lhs->offset,
@ -284,7 +468,6 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
lhs->shift_left = shift.U32();
}
return lhs;
break;
}
case IR::Opcode::BitwiseAnd32: {
IR::Value op1{inst->Arg(0)};
@ -310,10 +493,11 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
}
std::optional lhs{TrackCached(op1, env)};
if (lhs) {
lhs->shift_left = static_cast<u32>(std::countr_zero(op2.U32()));
if (op2.IsImmediate()) {
lhs->shift_left = static_cast<u32>(std::countr_zero(op2.U32()));
}
}
return lhs;
break;
}
case IR::Opcode::GetCbufU32x2:
case IR::Opcode::GetCbufU32:
@ -367,15 +551,42 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
};
}
// TODO:xbzk: shall be dropped when Track method cover all bindless stuff
static ConstBufferAddr last_valid_addr = ConstBufferAddr{
.index = 0,
.offset = 0,
.shift_left = 0,
.secondary_index = 0,
.secondary_offset = 0,
.secondary_shift_left = 0,
.dynamic_offset = {},
.count = 1,
.has_secondary = false,
};
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
ConstBufferAddr addr;
if (IsBindless(inst)) {
const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env)};
if (!track_addr) {
throw NotImplementedException("Failed to track bindless texture constant buffer");
//throw NotImplementedException("Failed to track bindless texture constant buffer");
LOG_DEBUG(Render_Vulkan, "!!! TRACKING FAILED !!! Using fallback - last_valid: cbuf[{}][{}]",
last_valid_addr.index, last_valid_addr.offset);
addr = last_valid_addr; // TODO:xbzk: shall be dropped when Track method cover all bindless stuff
} else {
addr = *track_addr;
if (addr.count == 1 && addr.dynamic_offset.IsEmpty()) {
u32 handle = GetTextureHandle(env, addr);
LOG_DEBUG(Render_Vulkan, "SUCCESS: cbuf[{}][{}] = HANDLE 0x{:08X}",
addr.index, addr.offset, handle);
} else {
LOG_DEBUG(Render_Vulkan, "SUCCESS: cbuf[{}][{}] (dynamic, count={})",
addr.index, addr.offset, addr.count);
}
last_valid_addr = addr; // TODO:xbzk: shall be dropped when Track method cover all bindless stuff
}
} else {
addr = ConstBufferAddr{
@ -590,12 +801,21 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
program.info.image_descriptors,
};
for (TextureInst& texture_inst : to_replace) {
// TODO: Handle arrays
IR::Inst* const inst{texture_inst.inst};
LOG_DEBUG(Render_Vulkan, "Pre Processing texture inst: opcode={}",
inst->GetOpcode());
// TODO: Handle arrays
inst->ReplaceOpcode(IndexedInstruction(*inst));
const auto& cbuf{texture_inst.cbuf};
auto flags{inst->Flags<IR::TextureInstInfo>()};
LOG_DEBUG(Render_Vulkan, "Post Processing texture inst: opcode={}, type={}, cbuf[{}][{}]",
inst->GetOpcode(), static_cast<int>(flags.type.Value()),
cbuf.index, cbuf.offset);
bool is_multisample{false};
switch (inst->GetOpcode()) {
case IR::Opcode::ImageQueryDimensions:
@ -646,6 +866,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
case IR::Opcode::ImageAtomicXor32:
case IR::Opcode::ImageAtomicExchange32:
case IR::Opcode::ImageWrite: {
LOG_DEBUG(Render_Vulkan, " -> Image read/write path");
if (cbuf.has_secondary) {
throw NotImplementedException("Unexpected separate sampler");
}
@ -679,7 +900,9 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
break;
}
default:
LOG_DEBUG(Render_Vulkan, " -> Default path, adding descriptor");
if (flags.type == TextureType::Buffer) {
LOG_DEBUG(Render_Vulkan, " -> Adding TextureBufferDescriptor");
index = descriptors.Add(TextureBufferDescriptor{
.has_secondary = cbuf.has_secondary,
.cbuf_index = cbuf.index,
@ -692,6 +915,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
.size_shift = DESCRIPTOR_SIZE_SHIFT,
});
} else {
LOG_DEBUG(Render_Vulkan, " -> Adding TextureDescriptor at cbuf[{}][{}]", cbuf.index, cbuf.offset);
index = descriptors.Add(TextureDescriptor{
.type = flags.type,
.is_depth = flags.is_depth != 0,
@ -706,6 +930,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
.count = cbuf.count,
.size_shift = DESCRIPTOR_SIZE_SHIFT,
});
LOG_DEBUG(Render_Vulkan, " -> Assigned descriptor index {}", index);
}
break;
}

33
src/video_core/renderer_vulkan/pipeline_helper.h

@ -184,13 +184,42 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
const u32 num_image_buffers = Shader::NumDescriptors(info.image_buffer_descriptors);
views += num_texture_buffers;
views += num_image_buffers;
bool fix_shadows = Settings::values.hack_fix_shadowarray.GetValue();
for (const auto& desc : info.texture_descriptors) {
VideoCommon::ImageViewId fallback_view_id = VideoCommon::NULL_IMAGE_VIEW_ID;
VideoCommon::SamplerId fallback_sampler_id = VideoCommon::NULL_SAMPLER_ID;
const VideoCommon::ImageViewInOut* temp_views = views;
const VideoCommon::SamplerId* temp_samplers = samplers;
if (fix_shadows) {
for (u32 index = 0; index < desc.count; ++index) {
if (temp_views[index].id != VideoCommon::NULL_IMAGE_VIEW_ID) {
fallback_view_id = temp_views[index].id;
fallback_sampler_id = temp_samplers[index];
break;
}
}
}
for (u32 index = 0; index < desc.count; ++index) {
const VideoCommon::ImageViewId image_view_id{(views++)->id};
const VideoCommon::SamplerId sampler_id{*(samplers++)};
ImageView& image_view{texture_cache.GetImageView(image_view_id)};
VideoCommon::ImageViewId actual_view_id = image_view_id;
VideoCommon::SamplerId actual_sampler_id = sampler_id;
if (fix_shadows &&
image_view_id == VideoCommon::NULL_IMAGE_VIEW_ID &&
fallback_view_id != VideoCommon::NULL_IMAGE_VIEW_ID) {
actual_view_id = fallback_view_id;
actual_sampler_id = fallback_sampler_id;
}
ImageView& image_view{texture_cache.GetImageView(actual_view_id)};
const VkImageView vk_image_view{image_view.Handle(desc.type)};
const Sampler& sampler{texture_cache.GetSampler(sampler_id)};
const Sampler& sampler{texture_cache.GetSampler(actual_sampler_id)};
const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
!image_view.SupportsAnisotropy()};
const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy()

9
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp

@ -393,6 +393,9 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
}
}
LOG_DEBUG(Render_Vulkan, "Stage {} Texture: cbuf[{}][{}] -> handle 0x{:08X}",
stage, desc.cbuf_index, desc.cbuf_offset + (index << desc.size_shift), handle.first);
if (handle.first == 0) {
views[view_index++] = {
.index = 0,
@ -432,8 +435,6 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
config_stage(4);
}
// Data exists in the slot the shadows want but it seems this outputs a invalid image for all of them.
// The problem is either inside this function or the texture_descriptors above is pulling junk data
texture_cache.FillGraphicsImageViews<Spec::has_images>(std::span(views.data(), view_index));
VideoCommon::ImageViewInOut* texture_buffer_it{views.data()};
@ -501,7 +502,9 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
buffer_cache.BindHostStageBuffers(stage);
PushImageDescriptors(texture_cache, guest_descriptor_queue, stage_infos[stage], rescaling,
samplers_it, views_it);
const auto& info{stage_infos[0]};
LOG_DEBUG(Render_Vulkan, "=== Preparing Stage {} ===", stage);
const Shader::Info& info{stage_infos[stage]};
LOG_DEBUG(Render_Vulkan, "Stage {} has {} texture descriptors", stage, info.texture_descriptors.size());
if (info.uses_render_area) {
render_area.uses_render_area = true;
render_area.words = {static_cast<float>(regs.surface_clip.width),

Loading…
Cancel
Save