1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-14 09:23:53 +01:00
dxvk/src/dxso/dxso_decoder.cpp

280 lines
8.3 KiB
C++

#include "dxso_decoder.h"
#include "dxso_tables.h"
namespace dxvk {
bool DxsoSemantic::operator== (const DxsoSemantic& b) const {
return usage == b.usage && usageIndex == b.usageIndex;
}
bool DxsoSemantic::operator!= (const DxsoSemantic& b) const {
return usage != b.usage || usageIndex != b.usageIndex;
}
uint32_t DxsoDecodeContext::decodeInstructionLength(uint32_t token) {
auto opcode = m_ctx.instruction.opcode;
uint32_t length = 0;
const auto& info = this->getProgramInfo();
// Comment ops have their own system for getting length.
if (opcode == DxsoOpcode::Comment)
return (token & 0x7fff0000) >> 16;
if (opcode == DxsoOpcode::End)
return 0;
// SM2.0 and above has the length of the op in instruction count baked into it.
// SM1.4 and below have fixed lengths and run off expectation.
// Phase does not respect the following rules. :shrug:
if (opcode != DxsoOpcode::Phase) {
if (info.majorVersion() >= 2)
length = (token & 0x0f000000) >> 24;
else
length = DxsoGetDefaultOpcodeLength(opcode);
}
// We've already logged this...
if (length == InvalidOpcodeLength)
return 0;
// SM 1.4 has an extra param on Tex and TexCoord
// As stated before, it also doesn't have the length of the op baked into the opcode
if (info.majorVersion() == 1
&& info.minorVersion() == 4) {
switch (opcode) {
case DxsoOpcode::TexCoord:
case DxsoOpcode::Tex: length += 1;
default: break;
}
}
return length;
}
bool DxsoDecodeContext::relativeAddressingUsesToken(
DxsoInstructionArgumentType type) {
auto& info = this->getProgramInfo();
return (info.majorVersion() >= 2 && type == DxsoInstructionArgumentType::Source)
|| (info.majorVersion() >= 3 && type == DxsoInstructionArgumentType::Destination);
}
void DxsoDecodeContext::decodeDeclaration(DxsoCodeIter& iter) {
uint32_t dclToken = iter.read();
m_ctx.dcl.textureType = static_cast<DxsoTextureType>((dclToken & 0x78000000) >> 27);
m_ctx.dcl.semantic.usage = static_cast<DxsoUsage>(dclToken & 0x0000000f);
m_ctx.dcl.semantic.usageIndex = (dclToken & 0x000f0000) >> 16;
}
void DxsoDecodeContext::decodeDefinition(DxsoOpcode opcode, DxsoCodeIter& iter) {
const uint32_t instructionLength = std::min(m_ctx.instruction.tokenLength - 1, 4u);
for (uint32_t i = 0; i < instructionLength; i++)
m_ctx.def.uint32[i] = iter.read();
}
void DxsoDecodeContext::decodeBaseRegister(
DxsoBaseRegister& reg,
uint32_t token) {
reg.id.type = static_cast<DxsoRegisterType>(
((token & 0x00001800) >> 8)
| ((token & 0x70000000) >> 28));
reg.id.num = token & 0x000007ff;
}
void DxsoDecodeContext::decodeGenericRegister(
DxsoRegister& reg,
uint32_t token) {
this->decodeBaseRegister(reg, token);
reg.hasRelative = (token & (1 << 13)) == 8192;
reg.relative.id = DxsoRegisterId {
DxsoRegisterType::Addr, 0 };
reg.relative.swizzle = IdentitySwizzle;
reg.centroid = token & (4 << 20);
reg.partialPrecision = token & (2 << 20);
}
void DxsoDecodeContext::decodeRelativeRegister(
DxsoBaseRegister& reg,
uint32_t token) {
this->decodeBaseRegister(reg, token);
reg.swizzle = DxsoRegSwizzle(
uint8_t((token & 0x00ff0000) >> 16));
}
bool DxsoDecodeContext::decodeDestinationRegister(DxsoCodeIter& iter) {
uint32_t token = iter.read();
this->decodeGenericRegister(m_ctx.dst, token);
m_ctx.dst.mask = DxsoRegMask(
uint8_t((token & 0x000f0000) >> 16));
m_ctx.dst.saturate = (token & (1 << 20)) != 0;
m_ctx.dst.shift = (token & 0x0f000000) >> 24;
m_ctx.dst.shift = (m_ctx.dst.shift & 0x7) - (m_ctx.dst.shift & 0x8);
const bool extraToken =
relativeAddressingUsesToken(DxsoInstructionArgumentType::Destination);
if (m_ctx.dst.hasRelative && extraToken) {
this->decodeRelativeRegister(m_ctx.dst.relative, iter.read());
return true;
}
return false;
}
bool DxsoDecodeContext::decodeSourceRegister(uint32_t i, DxsoCodeIter& iter) {
if (i >= m_ctx.src.size())
throw DxvkError("DxsoDecodeContext::decodeSourceRegister: source register out of range.");
uint32_t token = iter.read();
this->decodeGenericRegister(m_ctx.src[i], token);
m_ctx.src[i].swizzle = DxsoRegSwizzle(
uint8_t((token & 0x00ff0000) >> 16));
m_ctx.src[i].modifier = static_cast<DxsoRegModifier>(
(token & 0x0f000000) >> 24);
const bool extraToken =
relativeAddressingUsesToken(DxsoInstructionArgumentType::Source);
if (m_ctx.src[i].hasRelative && extraToken) {
this->decodeRelativeRegister(m_ctx.src[i].relative, iter.read());
return true;
}
return false;
}
void DxsoDecodeContext::decodePredicateRegister(DxsoCodeIter& iter) {
uint32_t token = iter.read();
this->decodeGenericRegister(m_ctx.pred, token);
m_ctx.pred.swizzle = DxsoRegSwizzle(
uint8_t((token & 0x00ff0000) >> 16));
m_ctx.pred.modifier = static_cast<DxsoRegModifier>(
(token & 0x0f000000) >> 24);
}
bool DxsoDecodeContext::decodeInstruction(DxsoCodeIter& iter) {
uint32_t token = iter.read();
m_ctx.instructionIdx++;
m_ctx.instruction.opcode = static_cast<DxsoOpcode>(
token & 0x0000ffff);
m_ctx.instruction.predicated = token & (1 << 28);
m_ctx.instruction.coissue = token & 0x40000000;
m_ctx.instruction.specificData.uint32 =
(token & 0x00ff0000) >> 16;
m_ctx.instruction.tokenLength =
this->decodeInstructionLength(token);
uint32_t tokenLength =
m_ctx.instruction.tokenLength;
switch (m_ctx.instruction.opcode) {
case DxsoOpcode::If:
case DxsoOpcode::Ifc:
case DxsoOpcode::Rep:
case DxsoOpcode::Loop:
case DxsoOpcode::BreakC:
case DxsoOpcode::BreakP: {
uint32_t sourceIdx = 0;
for (uint32_t i = 0; i < tokenLength; i++) {
if (this->decodeSourceRegister(sourceIdx, iter))
i++;
sourceIdx++;
}
return true;
}
case DxsoOpcode::Dcl:
this->decodeDeclaration(iter);
this->decodeDestinationRegister(iter);
return true;
case DxsoOpcode::Def:
case DxsoOpcode::DefI:
case DxsoOpcode::DefB:
this->decodeDestinationRegister(iter);
this->decodeDefinition(
m_ctx.instruction.opcode, iter);
return true;
case DxsoOpcode::Comment:
iter = iter.skip(tokenLength);
return true;
default: {
uint32_t sourceIdx = 0;
for (uint32_t i = 0; i < tokenLength; i++) {
if (i == 0) {
if (this->decodeDestinationRegister(iter))
i++;
}
else if (i == 1 && m_ctx.instruction.predicated) {
// Relative addressing makes no sense
// for predicate registers.
this->decodePredicateRegister(iter);
}
else {
if (this->decodeSourceRegister(sourceIdx, iter))
i++;
sourceIdx++;
}
}
return true;
}
case DxsoOpcode::End:
return false;
}
}
std::ostream& operator << (std::ostream& os, DxsoUsage usage) {
switch (usage) {
case DxsoUsage::Position: os << "Position"; break;
case DxsoUsage::BlendWeight: os << "BlendWeight"; break;
case DxsoUsage::BlendIndices: os << "BlendIndices"; break;
case DxsoUsage::Normal: os << "Normal"; break;
case DxsoUsage::PointSize: os << "PointSize"; break;
case DxsoUsage::Texcoord: os << "Texcoord"; break;
case DxsoUsage::Tangent: os << "Tangent"; break;
case DxsoUsage::Binormal: os << "Binormal"; break;
case DxsoUsage::TessFactor: os << "TessFactor"; break;
case DxsoUsage::PositionT: os << "PositionT"; break;
case DxsoUsage::Color: os << "Color"; break;
case DxsoUsage::Fog: os << "Fog"; break;
case DxsoUsage::Depth: os << "Depth"; break;
case DxsoUsage::Sample: os << "Sample"; break;
default:
os << "Invalid Format (" << static_cast<uint32_t>(usage) << ")"; break;
}
return os;
}
}