|
|
@ -4,162 +4,15 @@ |
|
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
|
#include <boost/container/small_vector.hpp>
|
|
|
|
|
|
#include <boost/container/static_vector.hpp>
|
|
|
#include <boost/container/static_vector.hpp>
|
|
|
|
|
|
|
|
|
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
|
|
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
|
|
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
|
|
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
|
|
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
|
|
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
|
|
#include "shader_recompiler/backend/spirv/texture_helpers.h"
|
|
|
|
|
|
#include "shader_recompiler/frontend/ir/modifiers.h"
|
|
|
#include "shader_recompiler/frontend/ir/modifiers.h"
|
|
|
|
|
|
|
|
|
namespace Shader::Backend::SPIRV { |
|
|
namespace Shader::Backend::SPIRV { |
|
|
namespace { |
|
|
namespace { |
|
|
|
|
|
|
|
|
TextureType GetEffectiveType(const EmitContext& ctx, TextureType type) { |
|
|
|
|
|
return EffectiveTextureType(ctx.profile, type); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool HasLayerComponent(TextureType type) { |
|
|
|
|
|
switch (type) { |
|
|
|
|
|
case TextureType::ColorArray1D: |
|
|
|
|
|
case TextureType::ColorArray2D: |
|
|
|
|
|
case TextureType::ColorArrayCube: |
|
|
|
|
|
return true; |
|
|
|
|
|
default: |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
u32 BaseDimension(TextureType type) { |
|
|
|
|
|
switch (type) { |
|
|
|
|
|
case TextureType::Color1D: |
|
|
|
|
|
case TextureType::ColorArray1D: |
|
|
|
|
|
return 1; |
|
|
|
|
|
case TextureType::Color2D: |
|
|
|
|
|
case TextureType::Color2DRect: |
|
|
|
|
|
case TextureType::ColorArray2D: |
|
|
|
|
|
case TextureType::ColorCube: |
|
|
|
|
|
case TextureType::ColorArrayCube: |
|
|
|
|
|
return 2; |
|
|
|
|
|
case TextureType::Color3D: |
|
|
|
|
|
return 3; |
|
|
|
|
|
default: |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool IsFloatCoordType(IR::Type type) { |
|
|
|
|
|
switch (type) { |
|
|
|
|
|
case IR::Type::F32: |
|
|
|
|
|
case IR::Type::F32x2: |
|
|
|
|
|
case IR::Type::F32x3: |
|
|
|
|
|
case IR::Type::F32x4: |
|
|
|
|
|
return true; |
|
|
|
|
|
case IR::Type::U32: |
|
|
|
|
|
case IR::Type::U32x2: |
|
|
|
|
|
case IR::Type::U32x3: |
|
|
|
|
|
case IR::Type::U32x4: |
|
|
|
|
|
return false; |
|
|
|
|
|
default: |
|
|
|
|
|
throw InvalidArgument("Unsupported coordinate type {}", type); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
u32 NumComponents(IR::Type type) { |
|
|
|
|
|
switch (type) { |
|
|
|
|
|
case IR::Type::F32: |
|
|
|
|
|
case IR::Type::U32: |
|
|
|
|
|
return 1; |
|
|
|
|
|
case IR::Type::F32x2: |
|
|
|
|
|
case IR::Type::U32x2: |
|
|
|
|
|
return 2; |
|
|
|
|
|
case IR::Type::F32x3: |
|
|
|
|
|
case IR::Type::U32x3: |
|
|
|
|
|
return 3; |
|
|
|
|
|
case IR::Type::F32x4: |
|
|
|
|
|
case IR::Type::U32x4: |
|
|
|
|
|
return 4; |
|
|
|
|
|
default: |
|
|
|
|
|
throw InvalidArgument("Unsupported type for coordinate promotion {}", type); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Id ExtractComponent(EmitContext& ctx, Id value, IR::Type type, u32 index, bool is_float) { |
|
|
|
|
|
if (NumComponents(type) == 1) { |
|
|
|
|
|
return value; |
|
|
|
|
|
} |
|
|
|
|
|
const Id scalar_type{is_float ? ctx.F32[1] : ctx.U32[1]}; |
|
|
|
|
|
return ctx.OpCompositeExtract(scalar_type, value, index); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Id PromoteCoordinate(EmitContext& ctx, IR::Inst* inst, const IR::TextureInstInfo& info, |
|
|
|
|
|
Id coords) { |
|
|
|
|
|
if (!Needs1DPromotion(ctx.profile, info.type)) { |
|
|
|
|
|
return coords; |
|
|
|
|
|
} |
|
|
|
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool has_layer{HasLayerComponent(effective_type)}; |
|
|
|
|
|
const u32 target_base_dim{BaseDimension(effective_type)}; |
|
|
|
|
|
if (target_base_dim == 0) { |
|
|
|
|
|
return coords; |
|
|
|
|
|
} |
|
|
|
|
|
const IR::Type coord_type{inst->Arg(1).Type()}; |
|
|
|
|
|
const bool is_float{IsFloatCoordType(coord_type)}; |
|
|
|
|
|
const Id zero{is_float ? ctx.f32_zero_value : ctx.u32_zero_value}; |
|
|
|
|
|
const u32 total_components{NumComponents(coord_type)}; |
|
|
|
|
|
const u32 original_base_dim{total_components - (has_layer ? 1u : 0u)}; |
|
|
|
|
|
|
|
|
|
|
|
boost::container::small_vector<Id, 5> components; |
|
|
|
|
|
components.reserve(target_base_dim + (has_layer ? 1u : 0u)); |
|
|
|
|
|
for (u32 i = 0; i < original_base_dim; ++i) { |
|
|
|
|
|
components.push_back(ExtractComponent(ctx, coords, coord_type, i, is_float)); |
|
|
|
|
|
} |
|
|
|
|
|
if (components.empty()) { |
|
|
|
|
|
components.push_back(coords); |
|
|
|
|
|
} |
|
|
|
|
|
while (components.size() < target_base_dim) { |
|
|
|
|
|
components.push_back(zero); |
|
|
|
|
|
} |
|
|
|
|
|
if (has_layer) { |
|
|
|
|
|
const u32 layer_index{total_components == 1 ? 0u : total_components - 1u}; |
|
|
|
|
|
components.push_back(ExtractComponent(ctx, coords, coord_type, layer_index, is_float)); |
|
|
|
|
|
} |
|
|
|
|
|
const Id vector_type{is_float ? ctx.F32[components.size()] : ctx.U32[components.size()]}; |
|
|
|
|
|
return ctx.OpCompositeConstruct(vector_type, std::span{components.data(), components.size()}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Id PromoteOffset(EmitContext& ctx, const IR::Value& offset, Id offset_id, |
|
|
|
|
|
TextureType effective_type) { |
|
|
|
|
|
const u32 required_components{BaseDimension(effective_type)}; |
|
|
|
|
|
if (required_components <= 1 || offset.IsEmpty()) { |
|
|
|
|
|
return offset_id; |
|
|
|
|
|
} |
|
|
|
|
|
const IR::Type offset_type{offset.Type()}; |
|
|
|
|
|
const u32 existing_components{NumComponents(offset_type)}; |
|
|
|
|
|
if (existing_components >= required_components) { |
|
|
|
|
|
return offset_id; |
|
|
|
|
|
} |
|
|
|
|
|
boost::container::small_vector<Id, 3> components; |
|
|
|
|
|
components.reserve(required_components); |
|
|
|
|
|
if (existing_components == 1) { |
|
|
|
|
|
components.push_back(offset_id); |
|
|
|
|
|
} else { |
|
|
|
|
|
for (u32 i = 0; i < existing_components; ++i) { |
|
|
|
|
|
components.push_back(ctx.OpCompositeExtract(ctx.S32[1], offset_id, i)); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
while (components.size() < required_components) { |
|
|
|
|
|
components.push_back(ctx.SConst(0)); |
|
|
|
|
|
} |
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.S32[required_components], |
|
|
|
|
|
std::span{components.data(), components.size()}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
u32 ExpectedDerivativeComponents(TextureType type) { |
|
|
|
|
|
return BaseDimension(type); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class ImageOperands { |
|
|
class ImageOperands { |
|
|
public: |
|
|
public: |
|
|
[[maybe_unused]] static constexpr bool ImageSampleOffsetAllowed = false; |
|
|
[[maybe_unused]] static constexpr bool ImageSampleOffsetAllowed = false; |
|
|
@ -167,10 +20,8 @@ public: |
|
|
[[maybe_unused]] static constexpr bool ImageFetchOffsetAllowed = false; |
|
|
[[maybe_unused]] static constexpr bool ImageFetchOffsetAllowed = false; |
|
|
[[maybe_unused]] static constexpr bool ImageGradientOffsetAllowed = false; |
|
|
[[maybe_unused]] static constexpr bool ImageGradientOffsetAllowed = false; |
|
|
|
|
|
|
|
|
explicit ImageOperands(EmitContext& ctx, TextureType type, bool promote, |
|
|
|
|
|
bool has_bias, bool has_lod, bool has_lod_clamp, Id lod, |
|
|
|
|
|
const IR::Value& offset) |
|
|
|
|
|
: texture_type{type}, needs_promotion{promote} { |
|
|
|
|
|
|
|
|
explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp, |
|
|
|
|
|
Id lod, const IR::Value& offset) { |
|
|
if (has_bias) { |
|
|
if (has_bias) { |
|
|
const Id bias{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod}; |
|
|
const Id bias{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod}; |
|
|
Add(spv::ImageOperandsMask::Bias, bias); |
|
|
Add(spv::ImageOperandsMask::Bias, bias); |
|
|
@ -186,11 +37,12 @@ public: |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
explicit ImageOperands(EmitContext& ctx, TextureType type, bool promote, |
|
|
|
|
|
const IR::Value& offset, const IR::Value& offset2) |
|
|
|
|
|
: texture_type{type}, needs_promotion{promote} { |
|
|
|
|
|
|
|
|
explicit ImageOperands(EmitContext& ctx, const IR::Value& offset, const IR::Value& offset2) { |
|
|
if (offset2.IsEmpty()) { |
|
|
if (offset2.IsEmpty()) { |
|
|
AddOffset(ctx, offset, ImageGatherOffsetAllowed); |
|
|
|
|
|
|
|
|
if (offset.IsEmpty()) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
Add(spv::ImageOperandsMask::Offset, ctx.Def(offset)); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
const std::array values{offset.InstRecursive(), offset2.InstRecursive()}; |
|
|
const std::array values{offset.InstRecursive(), offset2.InstRecursive()}; |
|
|
@ -220,10 +72,8 @@ public: |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
explicit ImageOperands(EmitContext& ctx, TextureType type, bool promote, bool has_lod_clamp, |
|
|
|
|
|
Id derivatives, u32 num_derivatives, const IR::Value& offset, |
|
|
|
|
|
Id lod_clamp) |
|
|
|
|
|
: texture_type{type}, needs_promotion{promote} { |
|
|
|
|
|
|
|
|
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives, |
|
|
|
|
|
u32 num_derivatives, const IR::Value& offset, Id lod_clamp) { |
|
|
if (!Sirit::ValidId(derivatives)) { |
|
|
if (!Sirit::ValidId(derivatives)) { |
|
|
throw LogicError("Derivatives must be present"); |
|
|
throw LogicError("Derivatives must be present"); |
|
|
} |
|
|
} |
|
|
@ -233,16 +83,10 @@ public: |
|
|
deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2)); |
|
|
deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2)); |
|
|
deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2 + 1)); |
|
|
deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2 + 1)); |
|
|
} |
|
|
} |
|
|
const u32 expected_components{needs_promotion ? ExpectedDerivativeComponents(texture_type) |
|
|
|
|
|
: num_derivatives}; |
|
|
|
|
|
while (needs_promotion && deriv_x_accum.size() < expected_components) { |
|
|
|
|
|
deriv_x_accum.push_back(ctx.f32_zero_value); |
|
|
|
|
|
deriv_y_accum.push_back(ctx.f32_zero_value); |
|
|
|
|
|
} |
|
|
|
|
|
const Id derivatives_X{ctx.OpCompositeConstruct( |
|
|
const Id derivatives_X{ctx.OpCompositeConstruct( |
|
|
ctx.F32[expected_components], std::span{deriv_x_accum.data(), deriv_x_accum.size()})}; |
|
|
|
|
|
|
|
|
ctx.F32[num_derivatives], std::span{deriv_x_accum.data(), deriv_x_accum.size()})}; |
|
|
const Id derivatives_Y{ctx.OpCompositeConstruct( |
|
|
const Id derivatives_Y{ctx.OpCompositeConstruct( |
|
|
ctx.F32[expected_components], std::span{deriv_y_accum.data(), deriv_y_accum.size()})}; |
|
|
|
|
|
|
|
|
ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})}; |
|
|
Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y); |
|
|
Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y); |
|
|
AddOffset(ctx, offset, ImageGradientOffsetAllowed); |
|
|
AddOffset(ctx, offset, ImageGradientOffsetAllowed); |
|
|
if (has_lod_clamp) { |
|
|
if (has_lod_clamp) { |
|
|
@ -250,10 +94,8 @@ public: |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
explicit ImageOperands(EmitContext& ctx, TextureType type, bool promote, bool has_lod_clamp, |
|
|
|
|
|
Id derivatives_1, Id derivatives_2, const IR::Value& offset, |
|
|
|
|
|
Id lod_clamp) |
|
|
|
|
|
: texture_type{type}, needs_promotion{promote} { |
|
|
|
|
|
|
|
|
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2, |
|
|
|
|
|
const IR::Value& offset, Id lod_clamp) { |
|
|
if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) { |
|
|
if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) { |
|
|
throw LogicError("Derivatives must be present"); |
|
|
throw LogicError("Derivatives must be present"); |
|
|
} |
|
|
} |
|
|
@ -295,62 +137,38 @@ private: |
|
|
if (offset.IsEmpty()) { |
|
|
if (offset.IsEmpty()) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
const u32 required_components{BaseDimension(texture_type)}; |
|
|
|
|
|
const bool promote_offset{needs_promotion && required_components > 1}; |
|
|
|
|
|
|
|
|
|
|
|
auto build_const_offset{[&](const boost::container::small_vector<s32, 3>& values) -> Id { |
|
|
|
|
|
switch (values.size()) { |
|
|
|
|
|
case 1: |
|
|
|
|
|
return ctx.SConst(values[0]); |
|
|
|
|
|
case 2: |
|
|
|
|
|
return ctx.SConst(values[0], values[1]); |
|
|
|
|
|
case 3: |
|
|
|
|
|
return ctx.SConst(values[0], values[1], values[2]); |
|
|
|
|
|
default: |
|
|
|
|
|
throw LogicError("Unsupported constant offset component count {}", |
|
|
|
|
|
values.size()); |
|
|
|
|
|
} |
|
|
|
|
|
}}; |
|
|
|
|
|
|
|
|
|
|
|
auto pad_components{[&](boost::container::small_vector<s32, 3>& components) { |
|
|
|
|
|
while (promote_offset && components.size() < required_components) { |
|
|
|
|
|
components.push_back(0); |
|
|
|
|
|
} |
|
|
|
|
|
}}; |
|
|
|
|
|
|
|
|
|
|
|
if (offset.IsImmediate()) { |
|
|
if (offset.IsImmediate()) { |
|
|
boost::container::small_vector<s32, 3> components{ |
|
|
|
|
|
static_cast<s32>(offset.U32())}; |
|
|
|
|
|
pad_components(components); |
|
|
|
|
|
Add(spv::ImageOperandsMask::ConstOffset, build_const_offset(components)); |
|
|
|
|
|
|
|
|
Add(spv::ImageOperandsMask::ConstOffset, ctx.SConst(static_cast<s32>(offset.U32()))); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
IR::Inst* const inst{offset.InstRecursive()}; |
|
|
IR::Inst* const inst{offset.InstRecursive()}; |
|
|
if (inst->AreAllArgsImmediates()) { |
|
|
if (inst->AreAllArgsImmediates()) { |
|
|
switch (inst->GetOpcode()) { |
|
|
switch (inst->GetOpcode()) { |
|
|
case IR::Opcode::CompositeConstructU32x2: |
|
|
case IR::Opcode::CompositeConstructU32x2: |
|
|
|
|
|
Add(spv::ImageOperandsMask::ConstOffset, |
|
|
|
|
|
ctx.SConst(static_cast<s32>(inst->Arg(0).U32()), |
|
|
|
|
|
static_cast<s32>(inst->Arg(1).U32()))); |
|
|
|
|
|
return; |
|
|
case IR::Opcode::CompositeConstructU32x3: |
|
|
case IR::Opcode::CompositeConstructU32x3: |
|
|
case IR::Opcode::CompositeConstructU32x4: { |
|
|
|
|
|
boost::container::small_vector<s32, 3> components; |
|
|
|
|
|
for (u32 i = 0; i < inst->NumArgs(); ++i) { |
|
|
|
|
|
components.push_back(static_cast<s32>(inst->Arg(i).U32())); |
|
|
|
|
|
} |
|
|
|
|
|
pad_components(components); |
|
|
|
|
|
Add(spv::ImageOperandsMask::ConstOffset, build_const_offset(components)); |
|
|
|
|
|
|
|
|
Add(spv::ImageOperandsMask::ConstOffset, |
|
|
|
|
|
ctx.SConst(static_cast<s32>(inst->Arg(0).U32()), |
|
|
|
|
|
static_cast<s32>(inst->Arg(1).U32()), |
|
|
|
|
|
static_cast<s32>(inst->Arg(2).U32()))); |
|
|
|
|
|
return; |
|
|
|
|
|
case IR::Opcode::CompositeConstructU32x4: |
|
|
|
|
|
Add(spv::ImageOperandsMask::ConstOffset, |
|
|
|
|
|
ctx.SConst(static_cast<s32>(inst->Arg(0).U32()), |
|
|
|
|
|
static_cast<s32>(inst->Arg(1).U32()), |
|
|
|
|
|
static_cast<s32>(inst->Arg(2).U32()), |
|
|
|
|
|
static_cast<s32>(inst->Arg(3).U32()))); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
|
|
|
default: |
|
|
default: |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
if (!runtime_offset_allowed) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
Id offset_id{ctx.Def(offset)}; |
|
|
|
|
|
if (promote_offset) { |
|
|
|
|
|
offset_id = PromoteOffset(ctx, offset, offset_id, texture_type); |
|
|
|
|
|
|
|
|
if (runtime_offset_allowed) { |
|
|
|
|
|
Add(spv::ImageOperandsMask::Offset, ctx.Def(offset)); |
|
|
} |
|
|
} |
|
|
Add(spv::ImageOperandsMask::Offset, offset_id); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Add(spv::ImageOperandsMask new_mask, Id value) { |
|
|
void Add(spv::ImageOperandsMask new_mask, Id value) { |
|
|
@ -366,8 +184,6 @@ private: |
|
|
operands.push_back(value_2); |
|
|
operands.push_back(value_2); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TextureType texture_type{TextureType::Color2D}; |
|
|
|
|
|
bool needs_promotion{}; |
|
|
|
|
|
boost::container::static_vector<Id, 4> operands; |
|
|
boost::container::static_vector<Id, 4> operands; |
|
|
spv::ImageOperandsMask mask{}; |
|
|
spv::ImageOperandsMask mask{}; |
|
|
}; |
|
|
}; |
|
|
@ -510,7 +326,8 @@ Id BitTest(EmitContext& ctx, Id mask, Id bit) { |
|
|
return ctx.OpINotEqual(ctx.U1, bit_value, ctx.u32_zero_value); |
|
|
return ctx.OpINotEqual(ctx.U1, bit_value, ctx.u32_zero_value); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Id ImageGatherSubpixelOffset(EmitContext& ctx, TextureType type, Id texture, Id coords) { |
|
|
|
|
|
|
|
|
Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info, Id texture, |
|
|
|
|
|
Id coords) { |
|
|
// Apply a subpixel offset of 1/512 the texel size of the texture to ensure same rounding on
|
|
|
// Apply a subpixel offset of 1/512 the texel size of the texture to ensure same rounding on
|
|
|
// AMD hardware as on Maxwell or other Nvidia architectures.
|
|
|
// AMD hardware as on Maxwell or other Nvidia architectures.
|
|
|
const auto calculate_coords{[&](size_t dim) { |
|
|
const auto calculate_coords{[&](size_t dim) { |
|
|
@ -521,7 +338,7 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, TextureType type, Id texture, Id |
|
|
offset = ctx.OpFDiv(ctx.F32[dim], offset, ctx.OpConvertUToF(ctx.F32[dim], image_size)); |
|
|
offset = ctx.OpFDiv(ctx.F32[dim], offset, ctx.OpConvertUToF(ctx.F32[dim], image_size)); |
|
|
return ctx.OpFAdd(ctx.F32[dim], coords, offset); |
|
|
return ctx.OpFAdd(ctx.F32[dim], coords, offset); |
|
|
}}; |
|
|
}}; |
|
|
switch (type) { |
|
|
|
|
|
|
|
|
switch (info.type) { |
|
|
case TextureType::Color2D: |
|
|
case TextureType::Color2D: |
|
|
case TextureType::Color2DRect: |
|
|
case TextureType::Color2DRect: |
|
|
return calculate_coords(2); |
|
|
return calculate_coords(2); |
|
|
@ -533,24 +350,14 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, TextureType type, Id texture, Id |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void AddOffsetToCoordinates(EmitContext& ctx, TextureType type, bool promoted_from_1d, Id& coords, |
|
|
|
|
|
|
|
|
void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, Id& coords, |
|
|
Id offset) { |
|
|
Id offset) { |
|
|
if (!Sirit::ValidId(offset)) { |
|
|
if (!Sirit::ValidId(offset)) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
auto PadScalarOffset = [&](u32 components) { |
|
|
|
|
|
boost::container::static_vector<Id, 3> elems; |
|
|
|
|
|
elems.push_back(offset); |
|
|
|
|
|
while (elems.size() < components) { |
|
|
|
|
|
elems.push_back(ctx.u32_zero_value); |
|
|
|
|
|
} |
|
|
|
|
|
offset = ctx.OpCompositeConstruct(ctx.U32[components], |
|
|
|
|
|
std::span{elems.data(), elems.size()}); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Id result_type{}; |
|
|
Id result_type{}; |
|
|
switch (type) { |
|
|
|
|
|
|
|
|
switch (info.type) { |
|
|
case TextureType::Buffer: |
|
|
case TextureType::Buffer: |
|
|
case TextureType::Color1D: { |
|
|
case TextureType::Color1D: { |
|
|
result_type = ctx.U32[1]; |
|
|
result_type = ctx.U32[1]; |
|
|
@ -561,21 +368,13 @@ void AddOffsetToCoordinates(EmitContext& ctx, TextureType type, bool promoted_fr |
|
|
[[fallthrough]]; |
|
|
[[fallthrough]]; |
|
|
case TextureType::Color2D: |
|
|
case TextureType::Color2D: |
|
|
case TextureType::Color2DRect: { |
|
|
case TextureType::Color2DRect: { |
|
|
if (promoted_from_1d) { |
|
|
|
|
|
PadScalarOffset(2); |
|
|
|
|
|
} |
|
|
|
|
|
result_type = ctx.U32[2]; |
|
|
result_type = ctx.U32[2]; |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case TextureType::ColorArray2D: |
|
|
case TextureType::ColorArray2D: |
|
|
if (promoted_from_1d) { |
|
|
|
|
|
PadScalarOffset(3); |
|
|
|
|
|
} else { |
|
|
|
|
|
offset = ctx.OpCompositeConstruct(ctx.U32[3], |
|
|
|
|
|
ctx.OpCompositeExtract(ctx.U32[1], coords, 0), |
|
|
|
|
|
ctx.OpCompositeExtract(ctx.U32[1], coords, 1), |
|
|
|
|
|
ctx.u32_zero_value); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
offset = ctx.OpCompositeConstruct(ctx.U32[3], ctx.OpCompositeExtract(ctx.U32[1], coords, 0), |
|
|
|
|
|
ctx.OpCompositeExtract(ctx.U32[1], coords, 1), |
|
|
|
|
|
ctx.u32_zero_value); |
|
|
[[fallthrough]]; |
|
|
[[fallthrough]]; |
|
|
case TextureType::Color3D: { |
|
|
case TextureType::Color3D: { |
|
|
result_type = ctx.U32[3]; |
|
|
result_type = ctx.U32[3]; |
|
|
@ -689,15 +488,12 @@ Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& |
|
|
Id bias_lc, const IR::Value& offset) { |
|
|
Id bias_lc, const IR::Value& offset) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
|
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
const Id color_type{TextureColorResultType(ctx, def)}; |
|
|
const Id color_type{TextureColorResultType(ctx, def)}; |
|
|
const Id texture{Texture(ctx, info, index)}; |
|
|
const Id texture{Texture(ctx, info, index)}; |
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
Id color{}; |
|
|
Id color{}; |
|
|
if (ctx.stage == Stage::Fragment) { |
|
|
if (ctx.stage == Stage::Fragment) { |
|
|
const ImageOperands operands(ctx, effective_type, needs_promotion, info.has_bias != 0, |
|
|
|
|
|
false, info.has_lod_clamp != 0, bias_lc, offset); |
|
|
|
|
|
|
|
|
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, |
|
|
|
|
|
bias_lc, offset); |
|
|
color = Emit(&EmitContext::OpImageSparseSampleImplicitLod, |
|
|
color = Emit(&EmitContext::OpImageSparseSampleImplicitLod, |
|
|
&EmitContext::OpImageSampleImplicitLod, ctx, inst, color_type, texture, |
|
|
&EmitContext::OpImageSampleImplicitLod, ctx, inst, color_type, texture, |
|
|
coords, operands.MaskOptional(), operands.Span()); |
|
|
coords, operands.MaskOptional(), operands.Span()); |
|
|
@ -706,8 +502,7 @@ Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& |
|
|
// if the lod was explicitly zero. This may change on Turing with implicit compute
|
|
|
// if the lod was explicitly zero. This may change on Turing with implicit compute
|
|
|
// derivatives
|
|
|
// derivatives
|
|
|
const Id lod{ctx.Const(0.0f)}; |
|
|
const Id lod{ctx.Const(0.0f)}; |
|
|
const ImageOperands operands(ctx, effective_type, needs_promotion, false, true, |
|
|
|
|
|
info.has_lod_clamp != 0, lod, offset); |
|
|
|
|
|
|
|
|
const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod, offset); |
|
|
color = Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
|
|
color = Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
|
|
&EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type, texture, |
|
|
&EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type, texture, |
|
|
coords, operands.Mask(), operands.Span()); |
|
|
coords, operands.Mask(), operands.Span()); |
|
|
@ -719,12 +514,8 @@ Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& |
|
|
Id lod, const IR::Value& offset) { |
|
|
Id lod, const IR::Value& offset) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
|
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
const Id color_type{TextureColorResultType(ctx, def)}; |
|
|
const Id color_type{TextureColorResultType(ctx, def)}; |
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
const ImageOperands operands(ctx, effective_type, needs_promotion, false, true, false, lod, |
|
|
|
|
|
offset); |
|
|
|
|
|
|
|
|
const ImageOperands operands(ctx, false, true, false, lod, offset); |
|
|
const Id color{Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
|
|
const Id color{Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
|
|
&EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type, |
|
|
&EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type, |
|
|
Texture(ctx, info, index), coords, operands.Mask(), operands.Span())}; |
|
|
Texture(ctx, info, index), coords, operands.Mask(), operands.Span())}; |
|
|
@ -734,12 +525,9 @@ Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& |
|
|
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, |
|
|
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, |
|
|
Id coords, Id dref, Id bias_lc, const IR::Value& offset) { |
|
|
Id coords, Id dref, Id bias_lc, const IR::Value& offset) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
if (ctx.stage == Stage::Fragment) { |
|
|
if (ctx.stage == Stage::Fragment) { |
|
|
const ImageOperands operands(ctx, effective_type, needs_promotion, info.has_bias != 0, |
|
|
|
|
|
false, info.has_lod_clamp != 0, bias_lc, offset); |
|
|
|
|
|
|
|
|
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, |
|
|
|
|
|
bias_lc, offset); |
|
|
return Emit(&EmitContext::OpImageSparseSampleDrefImplicitLod, |
|
|
return Emit(&EmitContext::OpImageSparseSampleDrefImplicitLod, |
|
|
&EmitContext::OpImageSampleDrefImplicitLod, ctx, inst, ctx.F32[1], |
|
|
&EmitContext::OpImageSampleDrefImplicitLod, ctx, inst, ctx.F32[1], |
|
|
Texture(ctx, info, index), coords, dref, operands.MaskOptional(), |
|
|
Texture(ctx, info, index), coords, dref, operands.MaskOptional(), |
|
|
@ -748,8 +536,7 @@ Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va |
|
|
// Implicit lods in compute behave on hardware as if sampling from LOD 0.
|
|
|
// Implicit lods in compute behave on hardware as if sampling from LOD 0.
|
|
|
// This check is to ensure all drivers behave this way.
|
|
|
// This check is to ensure all drivers behave this way.
|
|
|
const Id lod{ctx.Const(0.0f)}; |
|
|
const Id lod{ctx.Const(0.0f)}; |
|
|
const ImageOperands operands(ctx, effective_type, needs_promotion, false, true, false, |
|
|
|
|
|
lod, offset); |
|
|
|
|
|
|
|
|
const ImageOperands operands(ctx, false, true, false, lod, offset); |
|
|
return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod, |
|
|
return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod, |
|
|
&EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1], |
|
|
&EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1], |
|
|
Texture(ctx, info, index), coords, dref, operands.Mask(), operands.Span()); |
|
|
Texture(ctx, info, index), coords, dref, operands.Mask(), operands.Span()); |
|
|
@ -759,11 +546,7 @@ Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va |
|
|
Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, |
|
|
Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, |
|
|
Id coords, Id dref, Id lod, const IR::Value& offset) { |
|
|
Id coords, Id dref, Id lod, const IR::Value& offset) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
const ImageOperands operands(ctx, effective_type, needs_promotion, false, true, false, lod, |
|
|
|
|
|
offset); |
|
|
|
|
|
|
|
|
const ImageOperands operands(ctx, false, true, false, lod, offset); |
|
|
return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod, |
|
|
return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod, |
|
|
&EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1], |
|
|
&EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1], |
|
|
Texture(ctx, info, index), coords, dref, operands.Mask(), operands.Span()); |
|
|
Texture(ctx, info, index), coords, dref, operands.Mask(), operands.Span()); |
|
|
@ -773,15 +556,11 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id |
|
|
const IR::Value& offset, const IR::Value& offset2) { |
|
|
const IR::Value& offset, const IR::Value& offset2) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
|
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
const Id color_type{TextureColorResultType(ctx, def)}; |
|
|
const Id color_type{TextureColorResultType(ctx, def)}; |
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
const ImageOperands operands(ctx, effective_type, needs_promotion, offset, offset2); |
|
|
|
|
|
|
|
|
const ImageOperands operands(ctx, offset, offset2); |
|
|
const Id texture{Texture(ctx, info, index)}; |
|
|
const Id texture{Texture(ctx, info, index)}; |
|
|
if (ctx.profile.need_gather_subpixel_offset) { |
|
|
if (ctx.profile.need_gather_subpixel_offset) { |
|
|
coords = ImageGatherSubpixelOffset(ctx, effective_type, TextureImage(ctx, info, index), |
|
|
|
|
|
coords); |
|
|
|
|
|
|
|
|
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords); |
|
|
} |
|
|
} |
|
|
const Id color{ |
|
|
const Id color{ |
|
|
Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, color_type, |
|
|
Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, color_type, |
|
|
@ -793,13 +572,9 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id |
|
|
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
|
|
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
|
|
const IR::Value& offset, const IR::Value& offset2, Id dref) { |
|
|
const IR::Value& offset, const IR::Value& offset2, Id dref) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
const ImageOperands operands(ctx, effective_type, needs_promotion, offset, offset2); |
|
|
|
|
|
|
|
|
const ImageOperands operands(ctx, offset, offset2); |
|
|
if (ctx.profile.need_gather_subpixel_offset) { |
|
|
if (ctx.profile.need_gather_subpixel_offset) { |
|
|
coords = ImageGatherSubpixelOffset(ctx, effective_type, TextureImage(ctx, info, index), |
|
|
|
|
|
coords); |
|
|
|
|
|
|
|
|
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords); |
|
|
} |
|
|
} |
|
|
return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst, |
|
|
return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst, |
|
|
ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.MaskOptional(), |
|
|
ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.MaskOptional(), |
|
|
@ -811,11 +586,8 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureDefinition* def = |
|
|
const TextureDefinition* def = |
|
|
info.type == TextureType::Buffer ? nullptr : &ctx.textures.at(info.descriptor_index); |
|
|
info.type == TextureType::Buffer ? nullptr : &ctx.textures.at(info.descriptor_index); |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
const Id result_type{def ? TextureColorResultType(ctx, *def) : ctx.F32[4]}; |
|
|
const Id result_type{def ? TextureColorResultType(ctx, *def) : ctx.F32[4]}; |
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
AddOffsetToCoordinates(ctx, effective_type, needs_promotion, coords, offset); |
|
|
|
|
|
|
|
|
AddOffsetToCoordinates(ctx, info, coords, offset); |
|
|
if (info.type == TextureType::Buffer) { |
|
|
if (info.type == TextureType::Buffer) { |
|
|
lod = Id{}; |
|
|
lod = Id{}; |
|
|
} |
|
|
} |
|
|
@ -836,54 +608,30 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c |
|
|
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, |
|
|
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, |
|
|
const IR::Value& skip_mips_val) { |
|
|
const IR::Value& skip_mips_val) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
const Id image{TextureImage(ctx, info, index)}; |
|
|
const Id image{TextureImage(ctx, info, index)}; |
|
|
const Id zero{ctx.u32_zero_value}; |
|
|
const Id zero{ctx.u32_zero_value}; |
|
|
const bool skip_mips{skip_mips_val.U1()}; |
|
|
const bool skip_mips{skip_mips_val.U1()}; |
|
|
const auto mips{[&] { return skip_mips ? zero : ctx.OpImageQueryLevels(ctx.U32[1], image); }}; |
|
|
const auto mips{[&] { return skip_mips ? zero : ctx.OpImageQueryLevels(ctx.U32[1], image); }}; |
|
|
const bool is_msaa{IsTextureMsaa(ctx, info)}; |
|
|
const bool is_msaa{IsTextureMsaa(ctx, info)}; |
|
|
const bool uses_lod{!is_msaa && info.type != TextureType::Buffer}; |
|
|
const bool uses_lod{!is_msaa && info.type != TextureType::Buffer}; |
|
|
|
|
|
|
|
|
const u32 query_components = effective_type == TextureType::Buffer |
|
|
|
|
|
? 1u |
|
|
|
|
|
: BaseDimension(effective_type) + |
|
|
|
|
|
(HasLayerComponent(effective_type) ? 1u : 0u); |
|
|
|
|
|
const Id query_type{ctx.U32[std::max(1u, query_components)]}; |
|
|
|
|
|
const Id size = uses_lod ? ctx.OpImageQuerySizeLod(query_type, image, lod) |
|
|
|
|
|
: ctx.OpImageQuerySize(query_type, image); |
|
|
|
|
|
const auto extract = [&](u32 index) -> Id { |
|
|
|
|
|
if (query_components == 1) { |
|
|
|
|
|
return size; |
|
|
|
|
|
} |
|
|
|
|
|
return ctx.OpCompositeExtract(ctx.U32[1], size, index); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const auto query{[&](Id type) { |
|
|
|
|
|
return uses_lod ? ctx.OpImageQuerySizeLod(type, image, lod) |
|
|
|
|
|
: ctx.OpImageQuerySize(type, image); |
|
|
|
|
|
}}; |
|
|
switch (info.type) { |
|
|
switch (info.type) { |
|
|
case TextureType::Color1D: |
|
|
case TextureType::Color1D: |
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], extract(0), zero, zero, mips()); |
|
|
|
|
|
case TextureType::ColorArray1D: { |
|
|
|
|
|
const Id width{extract(0)}; |
|
|
|
|
|
const Id layers{needs_promotion ? extract(2) : extract(1)}; |
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], width, layers, zero, mips()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips()); |
|
|
|
|
|
case TextureType::ColorArray1D: |
|
|
case TextureType::Color2D: |
|
|
case TextureType::Color2D: |
|
|
case TextureType::ColorCube: |
|
|
case TextureType::ColorCube: |
|
|
case TextureType::Color2DRect: { |
|
|
|
|
|
const Id width{extract(0)}; |
|
|
|
|
|
const Id height{extract(1)}; |
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], width, height, zero, mips()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
case TextureType::Color2DRect: |
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[2]), zero, mips()); |
|
|
case TextureType::ColorArray2D: |
|
|
case TextureType::ColorArray2D: |
|
|
case TextureType::Color3D: |
|
|
case TextureType::Color3D: |
|
|
case TextureType::ColorArrayCube: { |
|
|
|
|
|
const Id width{extract(0)}; |
|
|
|
|
|
const Id height{extract(1)}; |
|
|
|
|
|
const Id depth{extract(2)}; |
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], width, height, depth, mips()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
case TextureType::ColorArrayCube: |
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[3]), mips()); |
|
|
case TextureType::Buffer: |
|
|
case TextureType::Buffer: |
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], extract(0), zero, zero, mips()); |
|
|
|
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips()); |
|
|
} |
|
|
} |
|
|
throw LogicError("Unspecified image type {}", info.type.Value()); |
|
|
throw LogicError("Unspecified image type {}", info.type.Value()); |
|
|
} |
|
|
} |
|
|
@ -892,7 +640,6 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const Id zero{ctx.f32_zero_value}; |
|
|
const Id zero{ctx.f32_zero_value}; |
|
|
const Id sampler{Texture(ctx, info, index)}; |
|
|
const Id sampler{Texture(ctx, info, index)}; |
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
return ctx.OpCompositeConstruct(ctx.F32[4], ctx.OpImageQueryLod(ctx.F32[2], sampler, coords), |
|
|
return ctx.OpCompositeConstruct(ctx.F32[4], ctx.OpImageQueryLod(ctx.F32[2], sampler, coords), |
|
|
zero, zero); |
|
|
zero, zero); |
|
|
} |
|
|
} |
|
|
@ -901,16 +648,11 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I |
|
|
Id derivatives, const IR::Value& offset, Id lod_clamp) { |
|
|
Id derivatives, const IR::Value& offset, Id lod_clamp) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
|
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
|
|
const TextureType effective_type{GetEffectiveType(ctx, info.type)}; |
|
|
|
|
|
const bool needs_promotion{Needs1DPromotion(ctx.profile, info.type)}; |
|
|
|
|
|
const Id color_type{TextureColorResultType(ctx, def)}; |
|
|
const Id color_type{TextureColorResultType(ctx, def)}; |
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
const auto operands = info.num_derivatives == 3 |
|
|
const auto operands = info.num_derivatives == 3 |
|
|
? ImageOperands(ctx, effective_type, needs_promotion, |
|
|
|
|
|
info.has_lod_clamp != 0, derivatives, |
|
|
|
|
|
ctx.Def(offset), IR::Value{}, lod_clamp) |
|
|
|
|
|
: ImageOperands(ctx, effective_type, needs_promotion, |
|
|
|
|
|
info.has_lod_clamp != 0, derivatives, |
|
|
|
|
|
|
|
|
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, |
|
|
|
|
|
ctx.Def(offset), {}, lod_clamp) |
|
|
|
|
|
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, |
|
|
info.num_derivatives, offset, lod_clamp); |
|
|
info.num_derivatives, offset, lod_clamp); |
|
|
const Id color{Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
|
|
const Id color{Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
|
|
&EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type, |
|
|
&EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type, |
|
|
@ -924,7 +666,6 @@ Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id co |
|
|
LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host"); |
|
|
LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host"); |
|
|
return ctx.ConstantNull(ctx.U32[4]); |
|
|
return ctx.ConstantNull(ctx.U32[4]); |
|
|
} |
|
|
} |
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
const auto [image, is_integer] = Image(ctx, index, info); |
|
|
const auto [image, is_integer] = Image(ctx, index, info); |
|
|
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]}; |
|
|
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]}; |
|
|
Id color{Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, |
|
|
Id color{Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, |
|
|
@ -937,7 +678,6 @@ Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id co |
|
|
|
|
|
|
|
|
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { |
|
|
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
const auto info{inst->Flags<IR::TextureInstInfo>()}; |
|
|
coords = PromoteCoordinate(ctx, inst, info, coords); |
|
|
|
|
|
const auto [image, is_integer] = Image(ctx, index, info); |
|
|
const auto [image, is_integer] = Image(ctx, index, info); |
|
|
if (!is_integer) { |
|
|
if (!is_integer) { |
|
|
color = ctx.OpBitcast(ctx.F32[4], color); |
|
|
color = ctx.OpBitcast(ctx.F32[4], color); |
|
|
|