mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-08-03 11:23:49 +00:00
307 lines
13 KiB
C++
307 lines
13 KiB
C++
#include "common/assert.h"
|
|
#include "graphics/shader/recompiler/emitter/spirvEmitterInternal.h"
|
|
|
|
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
|
|
|
bool HasImageSampleFlag(const IR::Instruction& inst, uint32_t flag) {
|
|
return (inst.memory.image_sample_flags & flag) != 0;
|
|
}
|
|
|
|
ImageSampleLayout MakeImageSampleLayout(const IR::Instruction& inst, ImageViewKind view) {
|
|
ImageSampleLayout layout;
|
|
uint32_t cursor = 0;
|
|
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagOffset)) {
|
|
layout.offset = cursor++;
|
|
}
|
|
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagBias)) {
|
|
layout.bias = cursor++;
|
|
}
|
|
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagCompare)) {
|
|
layout.dref = cursor++;
|
|
}
|
|
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagDerivative)) {
|
|
const auto components = ImageViewSpatialComponents(view);
|
|
layout.grad_x = cursor;
|
|
cursor += components;
|
|
layout.grad_y = cursor;
|
|
cursor += components;
|
|
}
|
|
layout.coord = cursor;
|
|
cursor += ImageViewCoordinateComponents(view);
|
|
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagLod)) {
|
|
layout.lod = cursor++;
|
|
}
|
|
return layout;
|
|
}
|
|
|
|
uint32_t EmitImageCoordF32(EmitterState& state, const IR::Instruction& inst,
|
|
const ImageSampleLayout& layout, ImageViewKind view) {
|
|
const auto x = EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord);
|
|
const auto components = ImageViewCoordinateComponents(view);
|
|
if (components == 1u) {
|
|
return x;
|
|
}
|
|
const auto y = inst.memory.image_address_components > layout.coord + 1u
|
|
? EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord + 1u)
|
|
: EmitZeroF32(state);
|
|
const auto coord = state.builder.AllocateId();
|
|
if (components == 3u) {
|
|
const auto z = inst.memory.image_address_components > layout.coord + 2u
|
|
? EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord + 2u)
|
|
: EmitZeroF32(state);
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec3_float_type, coord, x, y, z});
|
|
} else {
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, coord, x, y});
|
|
}
|
|
return coord;
|
|
}
|
|
|
|
uint32_t EmitImageLodF32(EmitterState& state, const IR::Instruction& inst,
|
|
const ImageSampleLayout& layout) {
|
|
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagLevelZero) ||
|
|
layout.lod == NoImageComponent || inst.memory.image_address_components <= layout.lod) {
|
|
return EmitZeroF32(state);
|
|
}
|
|
return EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.lod);
|
|
}
|
|
|
|
uint32_t EmitImageDrefF32(EmitterState& state, const IR::Instruction& inst,
|
|
const ImageSampleLayout& layout) {
|
|
if (layout.dref == NoImageComponent || inst.memory.image_address_components <= layout.dref) {
|
|
return EmitZeroF32(state);
|
|
}
|
|
return EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.dref);
|
|
}
|
|
|
|
uint32_t EmitImageBiasF32(EmitterState& state, const IR::Instruction& inst,
|
|
const ImageSampleLayout& layout) {
|
|
if (layout.bias == NoImageComponent || inst.memory.image_address_components <= layout.bias) {
|
|
return EmitZeroF32(state);
|
|
}
|
|
return EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.bias);
|
|
}
|
|
|
|
uint32_t EmitImageGradientF32(EmitterState& state, const IR::Instruction& inst,
|
|
uint32_t first_component, ImageViewKind view) {
|
|
const auto x = inst.memory.image_address_components > first_component
|
|
? EmitImageAddressFloatLoad(state, inst, inst.src[0], first_component)
|
|
: EmitZeroF32(state);
|
|
const auto components = ImageViewSpatialComponents(view);
|
|
if (components == 1u) {
|
|
return x;
|
|
}
|
|
const auto y = inst.memory.image_address_components > first_component + 1u
|
|
? EmitImageAddressFloatLoad(state, inst, inst.src[0], first_component + 1u)
|
|
: EmitZeroF32(state);
|
|
const auto grad = state.builder.AllocateId();
|
|
if (components == 3u) {
|
|
const auto z = inst.memory.image_address_components > first_component + 2u
|
|
? EmitImageAddressFloatLoad(state, inst, inst.src[0],
|
|
first_component + 2u)
|
|
: EmitZeroF32(state);
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec3_float_type, grad, x, y, z});
|
|
} else {
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, grad, x, y});
|
|
}
|
|
return grad;
|
|
}
|
|
|
|
uint32_t EmitImagePackedOffsetI32(EmitterState& state, const IR::Instruction& inst,
|
|
const ImageSampleLayout& layout, ImageViewKind view) {
|
|
const auto components = ImageViewSpatialComponents(view);
|
|
if (layout.offset == NoImageComponent ||
|
|
inst.memory.image_address_components <= layout.offset) {
|
|
const auto zero = ConstantI32(state, 0);
|
|
if (components == 1u) {
|
|
return zero;
|
|
}
|
|
const auto ret = state.builder.AllocateId();
|
|
if (components == 3u) {
|
|
state.builder.AddFunction(
|
|
{OpCompositeConstruct, state.vec3_int_type, ret, zero, zero, zero});
|
|
} else {
|
|
state.builder.AddFunction(
|
|
{OpCompositeConstruct, state.vec2_int_type, ret, zero, zero});
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
const auto packed_bits = EmitImageAddressValueLoad(state, inst, inst.src[0], layout.offset);
|
|
const auto packed_i32 = state.builder.AllocateId();
|
|
const auto offset_x = state.builder.AllocateId();
|
|
state.builder.AddFunction({OpBitcast, state.int_type, packed_i32, packed_bits});
|
|
state.builder.AddFunction({OpBitFieldSExtract, state.int_type, offset_x, packed_i32,
|
|
ConstantI32(state, 0), ConstantI32(state, 6)});
|
|
if (components == 1u) {
|
|
return offset_x;
|
|
}
|
|
const auto offset_y = state.builder.AllocateId();
|
|
const auto offset = state.builder.AllocateId();
|
|
state.builder.AddFunction({OpBitFieldSExtract, state.int_type, offset_y, packed_i32,
|
|
ConstantI32(state, 8), ConstantI32(state, 6)});
|
|
if (components == 3u) {
|
|
const auto offset_z = state.builder.AllocateId();
|
|
state.builder.AddFunction({OpBitFieldSExtract, state.int_type, offset_z, packed_i32,
|
|
ConstantI32(state, 16), ConstantI32(state, 6)});
|
|
state.builder.AddFunction(
|
|
{OpCompositeConstruct, state.vec3_int_type, offset, offset_x, offset_y, offset_z});
|
|
} else {
|
|
state.builder.AddFunction(
|
|
{OpCompositeConstruct, state.vec2_int_type, offset, offset_x, offset_y});
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
uint32_t EmitImageCoordU32(EmitterState& state, const IR::Instruction& inst, ImageViewKind view) {
|
|
const auto x = EmitImageAddressValueLoad(state, inst, inst.src[1], 0);
|
|
const auto components = ImageViewCoordinateComponents(view);
|
|
if (components == 1u) {
|
|
return x;
|
|
}
|
|
const auto y = inst.memory.image_address_components > 1u
|
|
? EmitImageAddressValueLoad(state, inst, inst.src[1], 1)
|
|
: ConstantU32(state, 0);
|
|
const auto coord = state.builder.AllocateId();
|
|
if (components == 3u) {
|
|
const auto z = inst.memory.image_address_components > 2u
|
|
? EmitImageAddressValueLoad(state, inst, inst.src[1], 2)
|
|
: ConstantU32(state, 0);
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec3_uint_type, coord, x, y, z});
|
|
} else {
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec2_uint_type, coord, x, y});
|
|
}
|
|
return coord;
|
|
}
|
|
|
|
uint32_t EmitImageLoadCoordU32(EmitterState& state, const IR::Instruction& inst,
|
|
ImageViewKind view) {
|
|
const auto x = EmitImageAddressValueLoad(state, inst, inst.src[0], 0);
|
|
const auto components = ImageViewCoordinateComponents(view);
|
|
if (components == 1u) {
|
|
return x;
|
|
}
|
|
const auto y = inst.memory.image_address_components > 1u
|
|
? EmitImageAddressValueLoad(state, inst, inst.src[0], 1)
|
|
: ConstantU32(state, 0);
|
|
const auto coord = state.builder.AllocateId();
|
|
if (components == 3u) {
|
|
const auto z = inst.memory.image_address_components > 2u
|
|
? EmitImageAddressValueLoad(state, inst, inst.src[0], 2)
|
|
: ConstantU32(state, 0);
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec3_uint_type, coord, x, y, z});
|
|
} else {
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec2_uint_type, coord, x, y});
|
|
}
|
|
return coord;
|
|
}
|
|
|
|
uint32_t EmitImageMipLodU32(EmitterState& state, const IR::Instruction& inst,
|
|
const IR::Operand& address, ImageViewKind view) {
|
|
if (!inst.memory.image_has_mip || inst.memory.image_address_components == 0u) {
|
|
return ConstantU32(state, 0);
|
|
}
|
|
const auto lod_component = ImageViewCoordinateComponents(view);
|
|
if (inst.memory.image_address_components <= lod_component) {
|
|
return ConstantU32(state, 0);
|
|
}
|
|
return EmitImageAddressValueLoad(state, inst, address, lod_component);
|
|
}
|
|
|
|
uint32_t EmitImageQueryCoordF32(EmitterState& state, const IR::Instruction& inst,
|
|
ImageViewKind view) {
|
|
const auto x = EmitImageAddressFloatLoad(state, inst, inst.src[0], 0);
|
|
const auto components = ImageViewCoordinateComponents(view);
|
|
if (components == 1u) {
|
|
return x;
|
|
}
|
|
const auto y = inst.memory.image_address_components > 1u
|
|
? EmitImageAddressFloatLoad(state, inst, inst.src[0], 1)
|
|
: EmitZeroF32(state);
|
|
const auto coord = state.builder.AllocateId();
|
|
if (components == 3u) {
|
|
const auto z = inst.memory.image_address_components > 2u
|
|
? EmitImageAddressFloatLoad(state, inst, inst.src[0], 2)
|
|
: EmitZeroF32(state);
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec3_float_type, coord, x, y, z});
|
|
} else {
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, coord, x, y});
|
|
}
|
|
return coord;
|
|
}
|
|
|
|
uint32_t DmaskComponentIndex(uint32_t dmask, uint32_t component) {
|
|
uint32_t index = 0;
|
|
for (uint32_t i = 0; i < component; i++) {
|
|
index += (dmask >> i) & 1u;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
uint32_t EmitImageStoreComponentF32(EmitterState& state, const IR::Instruction& inst,
|
|
uint32_t component) {
|
|
const auto dmask = inst.memory.dmask != 0 ? inst.memory.dmask : 1u;
|
|
if (((dmask >> component) & 1u) == 0) {
|
|
return EmitZeroF32(state);
|
|
}
|
|
return EmitSequentialFloatLoad(state, inst.src[0], DmaskComponentIndex(dmask, component));
|
|
}
|
|
|
|
uint32_t InverseStorageSwizzleComponent(uint32_t swizzle, uint32_t component) {
|
|
const auto target = 4u + component;
|
|
for (uint32_t source = 0; source < 4u; source++) {
|
|
if (((swizzle >> (source * 3u)) & 0x7u) == target) {
|
|
return source;
|
|
}
|
|
}
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
uint32_t StorageImageSwizzle(const EmitterState& state, const IR::Instruction& inst) {
|
|
if (inst.memory.resource >= state.program.info.images.size()) {
|
|
EXIT("storage image instruction has no specialized swizzle\n");
|
|
}
|
|
return state.program.info.images[inst.memory.resource].storage_swizzle;
|
|
}
|
|
|
|
uint32_t EmitImageStoreTexelF32(EmitterState& state, const IR::Instruction& inst) {
|
|
const auto swizzle = StorageImageSwizzle(state, inst);
|
|
const auto component_value = [&](uint32_t component) {
|
|
const auto source = InverseStorageSwizzleComponent(swizzle, component);
|
|
return source < 4u ? EmitImageStoreComponentF32(state, inst, source) : EmitZeroF32(state);
|
|
};
|
|
const auto x = component_value(0);
|
|
const auto y = component_value(1);
|
|
const auto z = component_value(2);
|
|
const auto w = component_value(3);
|
|
const auto texel = state.builder.AllocateId();
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec4_float_type, texel, x, y, z, w});
|
|
return texel;
|
|
}
|
|
|
|
uint32_t EmitImageStoreComponentU32(EmitterState& state, const IR::Instruction& inst,
|
|
uint32_t component) {
|
|
const auto dmask = inst.memory.dmask != 0 ? inst.memory.dmask : 1u;
|
|
if (((dmask >> component) & 1u) == 0) {
|
|
return ConstantU32(state, 0);
|
|
}
|
|
return EmitSequentialValueLoad(state, inst.src[0], DmaskComponentIndex(dmask, component));
|
|
}
|
|
|
|
uint32_t EmitImageStoreTexelU32(EmitterState& state, const IR::Instruction& inst) {
|
|
const auto swizzle = StorageImageSwizzle(state, inst);
|
|
const auto component_value = [&](uint32_t component) {
|
|
const auto source = InverseStorageSwizzleComponent(swizzle, component);
|
|
return source < 4u ? EmitImageStoreComponentU32(state, inst, source)
|
|
: ConstantU32(state, 0);
|
|
};
|
|
const auto x = component_value(0);
|
|
const auto y = component_value(1);
|
|
const auto z = component_value(2);
|
|
const auto w = component_value(3);
|
|
const auto texel = state.builder.AllocateId();
|
|
state.builder.AddFunction({OpCompositeConstruct, state.vec4_uint_type, texel, x, y, z, w});
|
|
return texel;
|
|
}
|
|
|
|
} // namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter
|