shader: Partially implement texture cube array shadow

This implements texture cube arrays with shadow comparisons but doesn't
fix the asserts related to it.

Fixes out of bounds reads on swizzle constructors and makes them use
bounds checked ::at instead of the unsafe operator[].
This commit is contained in:
ReinUsesLisp 2020-10-28 17:11:24 -03:00
parent 725fcbb368
commit 657771bdcb
3 changed files with 37 additions and 25 deletions

View File

@ -39,8 +39,8 @@ using Operation = const OperationNode&;
constexpr std::array INTERNAL_FLAG_NAMES = {"ZERO", "SIGN", "CARRY", "OVERFLOW"}; constexpr std::array INTERNAL_FLAG_NAMES = {"ZERO", "SIGN", "CARRY", "OVERFLOW"};
char Swizzle(std::size_t component) { char Swizzle(std::size_t component) {
ASSERT(component < 4); static constexpr std::string_view SWIZZLE{"xyzw"};
return component["xyzw"]; return SWIZZLE.at(component);
} }
constexpr bool IsGenericAttribute(Attribute::Index index) { constexpr bool IsGenericAttribute(Attribute::Index index) {
@ -224,7 +224,7 @@ private:
std::string Visit(const Node& node); std::string Visit(const Node& node);
std::pair<std::string, std::size_t> BuildCoords(Operation); std::tuple<std::string, std::string, std::size_t> BuildCoords(Operation);
std::string BuildAoffi(Operation); std::string BuildAoffi(Operation);
std::string GlobalMemoryPointer(const GmemNode& gmem); std::string GlobalMemoryPointer(const GmemNode& gmem);
void Exit(); void Exit();
@ -1416,12 +1416,12 @@ std::string ARBDecompiler::Visit(const Node& node) {
return {}; return {};
} }
std::pair<std::string, std::size_t> ARBDecompiler::BuildCoords(Operation operation) { std::tuple<std::string, std::string, std::size_t> ARBDecompiler::BuildCoords(Operation operation) {
const auto& meta = std::get<MetaTexture>(operation.GetMeta()); const auto& meta = std::get<MetaTexture>(operation.GetMeta());
UNIMPLEMENTED_IF(meta.sampler.is_indexed); UNIMPLEMENTED_IF(meta.sampler.is_indexed);
UNIMPLEMENTED_IF(meta.sampler.is_shadow && meta.sampler.is_array &&
meta.sampler.type == Tegra::Shader::TextureType::TextureCube);
const bool is_extended = meta.sampler.is_shadow && meta.sampler.is_array &&
meta.sampler.type == Tegra::Shader::TextureType::TextureCube;
const std::size_t count = operation.GetOperandsCount(); const std::size_t count = operation.GetOperandsCount();
std::string temporary = AllocVectorTemporary(); std::string temporary = AllocVectorTemporary();
std::size_t i = 0; std::size_t i = 0;
@ -1429,12 +1429,21 @@ std::pair<std::string, std::size_t> ARBDecompiler::BuildCoords(Operation operati
AddLine("MOV.F {}.{}, {};", temporary, Swizzle(i), Visit(operation[i])); AddLine("MOV.F {}.{}, {};", temporary, Swizzle(i), Visit(operation[i]));
} }
if (meta.sampler.is_array) { if (meta.sampler.is_array) {
AddLine("I2F.S {}.{}, {};", temporary, Swizzle(i++), Visit(meta.array)); AddLine("I2F.S {}.{}, {};", temporary, Swizzle(i), Visit(meta.array));
++i;
} }
if (meta.sampler.is_shadow) { if (meta.sampler.is_shadow) {
AddLine("MOV.F {}.{}, {};", temporary, Swizzle(i++), Visit(meta.depth_compare)); std::string compare = Visit(meta.depth_compare);
if (is_extended) {
ASSERT(i == 4);
std::string extra_coord = AllocVectorTemporary();
AddLine("MOV.F {}.x, {};", extra_coord, compare);
return {fmt::format("{}, {}", temporary, extra_coord), extra_coord, 0};
} }
return {std::move(temporary), i}; AddLine("MOV.F {}.{}, {};", temporary, Swizzle(i), compare);
++i;
}
return {temporary, temporary, i};
} }
std::string ARBDecompiler::BuildAoffi(Operation operation) { std::string ARBDecompiler::BuildAoffi(Operation operation) {
@ -1859,7 +1868,7 @@ std::string ARBDecompiler::LogicalAddCarry(Operation operation) {
std::string ARBDecompiler::Texture(Operation operation) { std::string ARBDecompiler::Texture(Operation operation) {
const auto& meta = std::get<MetaTexture>(operation.GetMeta()); const auto& meta = std::get<MetaTexture>(operation.GetMeta());
const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index;
const auto [temporary, swizzle] = BuildCoords(operation); const auto [coords, temporary, swizzle] = BuildCoords(operation);
std::string_view opcode = "TEX"; std::string_view opcode = "TEX";
std::string extra; std::string extra;
@ -1888,7 +1897,7 @@ std::string ARBDecompiler::Texture(Operation operation) {
} }
} }
AddLine("{}.F {}, {},{} texture[{}], {}{};", opcode, temporary, temporary, extra, sampler_id, AddLine("{}.F {}, {},{} texture[{}], {}{};", opcode, temporary, coords, extra, sampler_id,
TextureType(meta), BuildAoffi(operation)); TextureType(meta), BuildAoffi(operation));
AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element)); AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element));
return fmt::format("{}.x", temporary); return fmt::format("{}.x", temporary);
@ -1897,7 +1906,7 @@ std::string ARBDecompiler::Texture(Operation operation) {
std::string ARBDecompiler::TextureGather(Operation operation) { std::string ARBDecompiler::TextureGather(Operation operation) {
const auto& meta = std::get<MetaTexture>(operation.GetMeta()); const auto& meta = std::get<MetaTexture>(operation.GetMeta());
const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index;
const auto [temporary, swizzle] = BuildCoords(operation); const auto [coords, temporary, swizzle] = BuildCoords(operation);
std::string comp; std::string comp;
if (!meta.sampler.is_shadow) { if (!meta.sampler.is_shadow) {
@ -1907,7 +1916,7 @@ std::string ARBDecompiler::TextureGather(Operation operation) {
AddLine("TXG.F {}, {}, texture[{}]{}, {}{};", temporary, temporary, sampler_id, comp, AddLine("TXG.F {}, {}, texture[{}]{}, {}{};", temporary, temporary, sampler_id, comp,
TextureType(meta), BuildAoffi(operation)); TextureType(meta), BuildAoffi(operation));
AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element)); AddLine("MOV.U {}.x, {}.{};", temporary, coords, Swizzle(meta.element));
return fmt::format("{}.x", temporary); return fmt::format("{}.x", temporary);
} }
@ -1945,13 +1954,13 @@ std::string ARBDecompiler::TextureQueryLod(Operation operation) {
std::string ARBDecompiler::TexelFetch(Operation operation) { std::string ARBDecompiler::TexelFetch(Operation operation) {
const auto& meta = std::get<MetaTexture>(operation.GetMeta()); const auto& meta = std::get<MetaTexture>(operation.GetMeta());
const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index;
const auto [temporary, swizzle] = BuildCoords(operation); const auto [coords, temporary, swizzle] = BuildCoords(operation);
if (!meta.sampler.is_buffer) { if (!meta.sampler.is_buffer) {
ASSERT(swizzle < 4); ASSERT(swizzle < 4);
AddLine("MOV.F {}.w, {};", temporary, Visit(meta.lod)); AddLine("MOV.F {}.w, {};", temporary, Visit(meta.lod));
} }
AddLine("TXF.F {}, {}, texture[{}], {}{};", temporary, temporary, sampler_id, TextureType(meta), AddLine("TXF.F {}, {}, texture[{}], {}{};", temporary, coords, sampler_id, TextureType(meta),
BuildAoffi(operation)); BuildAoffi(operation));
AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element)); AddLine("MOV.U {}.x, {}.{};", temporary, temporary, Swizzle(meta.element));
return fmt::format("{}.x", temporary); return fmt::format("{}.x", temporary);
@ -1962,7 +1971,7 @@ std::string ARBDecompiler::TextureGradient(Operation operation) {
const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index; const u32 sampler_id = device.GetBaseBindings(stage).sampler + meta.sampler.index;
const std::string ddx = AllocVectorTemporary(); const std::string ddx = AllocVectorTemporary();
const std::string ddy = AllocVectorTemporary(); const std::string ddy = AllocVectorTemporary();
const std::string coord = BuildCoords(operation).first; const std::string coord = std::get<1>(BuildCoords(operation));
const std::size_t num_components = meta.derivates.size() / 2; const std::size_t num_components = meta.derivates.size() / 2;
for (std::size_t index = 0; index < num_components; ++index) { for (std::size_t index = 0; index < num_components; ++index) {

View File

@ -2056,15 +2056,19 @@ private:
} }
Expression Texture(Operation operation) { Expression Texture(Operation operation) {
const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); const auto meta = std::get<MetaTexture>(operation.GetMeta());
ASSERT(meta); const bool separate_dc = meta.sampler.type == TextureType::TextureCube &&
meta.sampler.is_array && meta.sampler.is_shadow;
std::string expr = GenerateTexture( // TODO: Replace this with an array and make GenerateTexture use C++20 std::span
operation, "", {TextureOffset{}, TextureArgument{Type::Float, meta->bias}}); const std::vector<TextureIR> extras{
if (meta->sampler.is_shadow) { TextureOffset{},
expr = "vec4(" + expr + ')'; TextureArgument{Type::Float, meta.bias},
};
std::string expr = GenerateTexture(operation, "", extras, separate_dc);
if (meta.sampler.is_shadow) {
expr = fmt::format("vec4({})", expr);
} }
return {expr + GetSwizzle(meta->element), Type::Float}; return {expr + GetSwizzle(meta.element), Type::Float};
} }
Expression TextureLod(Operation operation) { Expression TextureLod(Operation operation) {

View File

@ -556,7 +556,6 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
const bool is_shadow = depth_compare != nullptr; const bool is_shadow = depth_compare != nullptr;
const bool is_bindless = bindless_reg.has_value(); const bool is_bindless = bindless_reg.has_value();
UNIMPLEMENTED_IF(texture_type == TextureType::TextureCube && is_array && is_shadow);
ASSERT_MSG(texture_type != TextureType::Texture3D || !is_array || !is_shadow, ASSERT_MSG(texture_type != TextureType::Texture3D || !is_array || !is_shadow,
"Illegal texture type"); "Illegal texture type");