mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-04 01:29:26 +01:00
[dxbc] Bound-check dynamically indexed input registers
Halo MCC reads undefined PS inputs otherwise.
This commit is contained in:
parent
7f4e25267c
commit
f17317061c
@ -281,7 +281,7 @@ namespace dxvk {
|
|||||||
return this->emitDclGlobalFlags(ins);
|
return this->emitDclGlobalFlags(ins);
|
||||||
|
|
||||||
case DxbcOpcode::DclIndexRange:
|
case DxbcOpcode::DclIndexRange:
|
||||||
return; // not needed for anything
|
return this->emitDclIndexRange(ins);
|
||||||
|
|
||||||
case DxbcOpcode::DclTemps:
|
case DxbcOpcode::DclTemps:
|
||||||
return this->emitDclTemps(ins);
|
return this->emitDclTemps(ins);
|
||||||
@ -375,6 +375,21 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxbcCompiler::emitDclIndexRange(const DxbcShaderInstruction& ins) {
|
||||||
|
// dcl_index_range has one operand:
|
||||||
|
// (0) Range start, either an input or output register
|
||||||
|
// (1) Range end
|
||||||
|
uint32_t index = ins.dst[0].idxDim - 1u;
|
||||||
|
|
||||||
|
DxbcIndexRange range = { };
|
||||||
|
range.type = ins.dst[0].type;
|
||||||
|
range.start = ins.dst[0].idx[index].offset;
|
||||||
|
range.length = ins.imm[0].u32;
|
||||||
|
|
||||||
|
m_indexRanges.push_back(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxbcCompiler::emitDclTemps(const DxbcShaderInstruction& ins) {
|
void DxbcCompiler::emitDclTemps(const DxbcShaderInstruction& ins) {
|
||||||
// dcl_temps has one operand:
|
// dcl_temps has one operand:
|
||||||
// (imm0) Number of temp registers
|
// (imm0) Number of temp registers
|
||||||
@ -5737,14 +5752,37 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxbcRegisterValue DxbcCompiler::emitRegisterLoadRaw(
|
DxbcRegisterValue DxbcCompiler::emitRegisterLoadRaw(
|
||||||
const DxbcRegister& reg) {
|
const DxbcRegister& reg) {
|
||||||
if (reg.type == DxbcOperandType::IndexableTemp) {
|
// Try to find index range for the given register
|
||||||
bool doBoundsCheck = reg.idx[1].relReg != nullptr;
|
const DxbcIndexRange* indexRange = nullptr;
|
||||||
DxbcRegisterValue vectorId = emitIndexLoad(reg.idx[1]);
|
|
||||||
|
if (reg.idxDim && reg.idx[reg.idxDim - 1u].relReg) {
|
||||||
|
uint32_t offset = reg.idx[reg.idxDim - 1u].offset;
|
||||||
|
|
||||||
|
for (const auto& range : m_indexRanges) {
|
||||||
|
if (reg.type == range.type && offset >= range.start && offset < range.start + range.length)
|
||||||
|
indexRange = ⦥
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg.type == DxbcOperandType::IndexableTemp || indexRange) {
|
||||||
|
bool doBoundsCheck = reg.idx[reg.idxDim - 1u].relReg != nullptr;
|
||||||
|
|
||||||
if (doBoundsCheck) {
|
if (doBoundsCheck) {
|
||||||
uint32_t boundsCheck = m_module.opULessThan(
|
DxbcRegisterValue indexId = emitIndexLoad(reg.idx[reg.idxDim - 1u]);
|
||||||
m_module.defBoolType(), vectorId.id,
|
uint32_t boundsCheck = 0u;
|
||||||
|
|
||||||
|
if (reg.type == DxbcOperandType::IndexableTemp) {
|
||||||
|
boundsCheck = m_module.opULessThan(
|
||||||
|
m_module.defBoolType(), indexId.id,
|
||||||
m_module.constu32(m_xRegs.at(reg.idx[0].offset).alength));
|
m_module.constu32(m_xRegs.at(reg.idx[0].offset).alength));
|
||||||
|
} else {
|
||||||
|
uint32_t adjustedId = m_module.opISub(getVectorTypeId(indexId.type),
|
||||||
|
indexId.id, m_module.consti32(indexRange->start));
|
||||||
|
|
||||||
|
boundsCheck = m_module.opULessThan(
|
||||||
|
m_module.defBoolType(), adjustedId,
|
||||||
|
m_module.constu32(indexRange->length));
|
||||||
|
}
|
||||||
|
|
||||||
// Kind of ugly to have an empty else block here but there's no
|
// Kind of ugly to have an empty else block here but there's no
|
||||||
// way for us to know the current block ID for the phi below
|
// way for us to know the current block ID for the phi below
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../spirv/spirv_module.h"
|
#include "../spirv/spirv_module.h"
|
||||||
@ -136,6 +137,13 @@ namespace dxvk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct DxbcIndexRange {
|
||||||
|
DxbcOperandType type;
|
||||||
|
uint32_t start;
|
||||||
|
uint32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Vertex shader-specific structure
|
* \brief Vertex shader-specific structure
|
||||||
*/
|
*/
|
||||||
@ -445,6 +453,10 @@ namespace dxvk {
|
|||||||
// xfb output registers for geometry shaders
|
// xfb output registers for geometry shaders
|
||||||
std::vector<DxbcXfbVar> m_xfbVars;
|
std::vector<DxbcXfbVar> m_xfbVars;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// Dynamically indexed input and output regs
|
||||||
|
std::vector<DxbcIndexRange> m_indexRanges = { };
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
// Shader resource variables. These provide access to
|
// Shader resource variables. These provide access to
|
||||||
// constant buffers, samplers, textures, and UAVs.
|
// constant buffers, samplers, textures, and UAVs.
|
||||||
@ -546,6 +558,9 @@ namespace dxvk {
|
|||||||
void emitDclGlobalFlags(
|
void emitDclGlobalFlags(
|
||||||
const DxbcShaderInstruction& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
|
void emitDclIndexRange(
|
||||||
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
void emitDclTemps(
|
void emitDclTemps(
|
||||||
const DxbcShaderInstruction& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user