Merge pull request #1388 from gjonn/feat/agc-color-compare-constant-swizzle
feat(agc): color compare through a view whose X channel is constant
This commit is contained in:
commit
4c9686fe2e
|
|
@ -47,7 +47,8 @@ constexpr std::array<std::uint8_t, 4> Red{0, 64, 128, 255};
|
|||
|
||||
alignas(256) std::array<float, Threads * 3> Input{};
|
||||
alignas(256) std::array<float, Threads * 4> CubeInput{};
|
||||
alignas(256) std::array<float, Threads> Output{};
|
||||
alignas(256) std::array<float, Threads * 4> Output{};
|
||||
std::uint32_t Swizzle = 0xfacu;
|
||||
alignas(256) std::array<std::uint32_t, Threads * 3> Extra{};
|
||||
alignas(4096) std::array<std::uint8_t, 4096> Texels{};
|
||||
|
||||
|
|
@ -71,6 +72,14 @@ alignas(256) constexpr std::array<std::uint32_t, 16> OffsetCode{
|
|||
0x7e0c0308, 0xf0f80108, 0x00820901, 0xbf8c3f70, 0x34160082, 0xe0701000, 0x8001090b, 0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 17> QuadCode{
|
||||
0x1614008c, 0xe03c1000, 0x8000010a, 0x7e0802f3, 0x7e0a02f3, 0x7e0c02f3, 0x7e0e02f3, 0xbf8c3f70, 0xf0bc0f08, 0x00820401, 0xbf8c3f70, 0x34160084, 0xe0781000, 0x8001040b, 0xbf810000, 0xbf810000, 0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 17> PairCode{
|
||||
0x1614008c, 0xe03c1000, 0x8000010a, 0x7e0802f3, 0x7e0a02f3, 0x7e0c02f3, 0x7e0e02f3, 0xbf8c3f70, 0xf0bc0608, 0x00820401, 0xbf8c3f70, 0x34160084, 0xe0781000, 0x8001040b, 0xbf810000, 0xbf810000, 0xbf810000,
|
||||
};
|
||||
|
||||
struct Sampler {
|
||||
std::uint32_t clamp;
|
||||
std::uint32_t filter;
|
||||
|
|
@ -91,7 +100,7 @@ std::array<std::uint32_t, 8> TextureDescriptor(std::uint32_t format, bool cube =
|
|||
static_cast<std::uint32_t>(address >> 8u),
|
||||
static_cast<std::uint32_t>((address >> 40u) & 0xffu) | (format << 20u) | (((Side - 1u) & 3u) << 30u),
|
||||
((Side - 1u) >> 2u) | ((Side - 1u) << 14u),
|
||||
0xfacu | ((cube ? TypeCube : Type2D) << 28u),
|
||||
Swizzle | ((cube ? TypeCube : Type2D) << 28u),
|
||||
cube ? 5u : 0u, 0u, 0u, 0u,
|
||||
};
|
||||
}
|
||||
|
|
@ -240,6 +249,32 @@ void Run(AgcDriver::VulkanDevice& device, const Sampler& sampler, const char* na
|
|||
}
|
||||
}
|
||||
|
||||
constexpr std::uint32_t Select(std::uint32_t x, std::uint32_t y, std::uint32_t z, std::uint32_t w) {
|
||||
return x | (y << 3u) | (z << 6u) | (w << 9u);
|
||||
}
|
||||
|
||||
void RunChannels(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, std::array<std::uint32_t, 4> channels, std::uint32_t registers, std::uint32_t firstChannel, const char* name) {
|
||||
const Sampler sampler{ClampEdge, FilterBilinear};
|
||||
Swizzle = Select(channels[0], channels[1], channels[2], channels[3]);
|
||||
Output.fill(-2.0f);
|
||||
const auto result = Compile(device, Format8888UNorm, sampler, code);
|
||||
Swizzle = 0xfacu;
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const float compared = Expected(tid, sampler, false);
|
||||
for (std::uint32_t reg = 0; reg < 4u; ++reg) {
|
||||
float expected = -1.0f;
|
||||
if (reg < registers) {
|
||||
const auto select = channels[firstChannel + reg];
|
||||
expected = select == 0u ? 0.0f : select == 1u ? 1.0f : compared;
|
||||
}
|
||||
const float actual = Output[tid * 4u + reg];
|
||||
Require(std::fabs(actual - expected) <= 1e-4f, std::string(name) + ": thread " + std::to_string(tid) + " register " + std::to_string(reg) + " returned " + std::to_string(actual) + ", expected " + std::to_string(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RunCube(AgcDriver::VulkanDevice& device, const Sampler& sampler, const char* name) {
|
||||
FillCubeTexels();
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
|
|
@ -313,6 +348,19 @@ int main() {
|
|||
Run(*device, {ClampWrap, FilterBilinear}, "cached bilinear comparison with offsets", true, true);
|
||||
}
|
||||
Reject(*device, Format32Float, {ClampEdge, FilterPoint}, "native comparison with a nonconstant texel offset requires", OffsetCode, false);
|
||||
RunChannels(*device, QuadCode, {4, 5, 6, 7}, 4, 0, "view R,G,B,A");
|
||||
RunChannels(*device, QuadCode, {0, 0, 0, 0}, 4, 0, "view 0,0,0,0");
|
||||
RunChannels(*device, QuadCode, {1, 1, 1, 1}, 4, 0, "view 1,1,1,1");
|
||||
RunChannels(*device, QuadCode, {0, 4, 1, 5}, 4, 0, "view 0,R,1,G");
|
||||
RunChannels(*device, QuadCode, {4, 0, 0, 1}, 4, 0, "view R,0,0,1");
|
||||
RunChannels(*device, QuadCode, {5, 4, 5, 6}, 4, 0, "view G,R,B,A");
|
||||
RunChannels(*device, QuadCode, {7, 4, 4, 4}, 4, 0, "view A,R,R,R");
|
||||
RunChannels(*device, PairCode, {0, 4, 4, 4}, 2, 1, "view 0,R,R,R, dmask 6");
|
||||
Swizzle = Select(4, 2, 4, 4);
|
||||
Reject(*device, Format8888UNorm, {ClampEdge, FilterPoint}, "every view channel is a constant or a color channel");
|
||||
Swizzle = Select(5, 5, 5, 5);
|
||||
Reject(*device, Format8888UNorm, {ClampEdge, FilterPoint}, "a view channel selects red");
|
||||
Swizzle = 0xfacu;
|
||||
Reject(*device, Format8888UInt, {ClampEdge, FilterPoint}, "unsupported format");
|
||||
Reject(*device, Format8888UNorm, {ClampMirror, FilterPoint}, "wrap, clamp-to-edge or clamp-to-border");
|
||||
Reject(*device, Format8888UNorm, {ClampHalfBorder, FilterPoint}, "wrap, clamp-to-edge or clamp-to-border");
|
||||
|
|
|
|||
|
|
@ -528,7 +528,15 @@ std::uint32_t emulatedCompareState(const ShaderInfo& info, const ResourceSnapsho
|
|||
const auto reference = colorCompareReference(format);
|
||||
const auto type = rawImageType(descriptor);
|
||||
if (type != ImageType::Color2D && type != ImageType::Color2DArray && type != ImageType::Cube) throw std::runtime_error("comparison sampling of a color texture is implemented only for 2D, 2D array and cube views");
|
||||
if ((descriptorImageSwizzle(descriptor) & 0x7u) != 4u) throw std::runtime_error("comparison sampling of a color texture is implemented only when the view's X channel is red");
|
||||
bool redChannel = false;
|
||||
bool compareChannel = false;
|
||||
for (std::uint32_t channel = 0u; channel < 4u; ++channel) {
|
||||
const auto select = (descriptorImageSwizzle(descriptor) >> (channel * 3u)) & 0x7u;
|
||||
if (select == 2u || select == 3u) throw std::runtime_error("comparison sampling of a color texture is implemented only when every view channel is a constant or a color channel");
|
||||
redChannel = redChannel || select == 4u;
|
||||
compareChannel = compareChannel || select >= 4u;
|
||||
}
|
||||
if (compareChannel && !redChannel) throw std::runtime_error("comparison sampling of a color texture is implemented only when a view channel selects red");
|
||||
std::optional<std::uint32_t> samplerState;
|
||||
for (const auto& pair : info.sampledPairs) {
|
||||
if (pair.image != index) continue;
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ std::uint32_t ResultVector(SpirvValueEmitContext& ctx, const ImageEmitAccess& ac
|
|||
std::uint32_t component[4] = {};
|
||||
for (std::uint32_t index = 0; index < 4u; index++) {
|
||||
if (dref) {
|
||||
component[index] = index == 0u ? F32BitsToU32(ctx, value) : ConstantU32(state, 0);
|
||||
component[index] = F32BitsToU32(ctx, value);
|
||||
continue;
|
||||
}
|
||||
const auto scalar = state.module.AllocateId();
|
||||
|
|
@ -1336,7 +1336,8 @@ void EmitEmulatedCompareSample(SpirvValueEmitContext& ctx, const ImageEmitAccess
|
|||
else state.module.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(state, 2), coord, ux, uy);
|
||||
const auto texel = state.module.AllocateId();
|
||||
state.module.AddFunction(spv::OpImageFetch, ImageVectorType(state, IrTextureNumericClass::Float, 4), texel, descriptor, coord, spv::ImageOperandsLodMask, ConstantU32(state, 0u));
|
||||
auto red = extract(f32, texel, 0u);
|
||||
auto red = extract(f32, texel, 3u);
|
||||
for (std::uint32_t channel = 3u; channel-- > 0u;) red = Select(state, f32, equal(RuntimeImageSwizzle(state, mem.resource, channel), 4u), extract(f32, texel, channel), red);
|
||||
red = Select(state, f32, equal(modeX, EmulatedCompare::AddressBorder), Select(state, f32, inside(x, width), red, borderRed), red);
|
||||
red = Select(state, f32, equal(modeY, EmulatedCompare::AddressBorder), Select(state, f32, inside(y, height), red, borderRed), red);
|
||||
constexpr std::array<spv::Op, 6> operations{spv::OpFOrdLessThan, spv::OpFOrdEqual, spv::OpFOrdLessThanEqual, spv::OpFOrdGreaterThan, spv::OpFOrdNotEqual, spv::OpFOrdGreaterThanEqual};
|
||||
|
|
@ -1377,7 +1378,15 @@ void EmitEmulatedCompareSample(SpirvValueEmitContext& ctx, const ImageEmitAccess
|
|||
const auto bottom = ext(f32, GLSLstd450FMix, {compareTexel(x0, y1), compareTexel(x1, y1), weightU});
|
||||
return ext(f32, GLSLstd450FMix, {top, bottom, weightV});
|
||||
});
|
||||
ctx.Define(access.inst, TableResult(ctx, access, ResultVector(ctx, access, result, setup.numericClass, true, false)));
|
||||
const auto channelResult = [&](std::uint32_t channel) {
|
||||
const auto selector = RuntimeImageSwizzle(state, mem.resource, channel);
|
||||
return Select(state, f32, equal(selector, 0u), zero, Select(state, f32, equal(selector, 1u), one, result));
|
||||
};
|
||||
std::uint32_t channels[4] = {};
|
||||
for (std::uint32_t channel = 0; channel < 4u; ++channel) channels[channel] = channelResult(channel);
|
||||
const auto value = state.module.AllocateId();
|
||||
state.module.AddFunction(spv::OpCompositeConstruct, TypeF32Vector(state, 4), value, channels[0], channels[1], channels[2], channels[3]);
|
||||
ctx.Define(access.inst, TableResult(ctx, access, ResultVector(ctx, access, value, IrTextureNumericClass::Float, false, false)));
|
||||
}
|
||||
|
||||
void EmitSampleOp(SpirvValueEmitContext& ctx, const ImageEmitAccess& access, const SampleSetup& setup) {
|
||||
|
|
|
|||
|
|
@ -204,15 +204,7 @@ bool TranslationContext::imageSample(const RdnaInstruction& inst) {
|
|||
IrValue* sampler = getSamplerResource(memory);
|
||||
IrValue* address = makeImageAddress(inst, inst.source0);
|
||||
IrValue& result = ir.Emit(IrOpcode::ImageSampleRaw, IrOpcodeType(IrOpcode::ImageSampleRaw), {resource, sampler, address}, addMemoryInfo(memory, inst.programCounter));
|
||||
const bool dref = (memory.imageSampleFlags & RdnaImageSampleFlagCompare) != 0u;
|
||||
if (dref && memory.dataBits != 16u) {
|
||||
IrValue& component = ir.CompositeExtract(result, 0u);
|
||||
for (std::uint32_t index = 0; index < memory.dataDwords; ++index) {
|
||||
writeOperand(offsetOperand(inst.destination, index), &component);
|
||||
}
|
||||
} else {
|
||||
writeImageComponents(inst.destination, &result, memory, 4u);
|
||||
}
|
||||
writeImageComponents(inst.destination, &result, memory, 4u);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue