Basic combined image sampler emulation hooked up.
This commit is contained in:
Родитель
1b5ca8d868
Коммит
71bacc4469
102
spirv_cross.cpp
102
spirv_cross.cpp
|
@ -2309,6 +2309,108 @@ bool Compiler::interface_variable_exists_in_entry_point(uint32_t id) const
|
|||
end(execution.interface_variables);
|
||||
}
|
||||
|
||||
bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *args, uint32_t length)
|
||||
{
|
||||
// We need to figure out where samplers and images are loaded from, so do only the bare bones compilation we need.
|
||||
switch (opcode)
|
||||
{
|
||||
case OpLoad:
|
||||
{
|
||||
if (length < 3)
|
||||
return false;
|
||||
|
||||
uint32_t result_type = args[0];
|
||||
|
||||
auto &type = compiler.get<SPIRType>(result_type);
|
||||
bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
|
||||
bool separate_sampler = type.basetype == SPIRType::Sampler;
|
||||
|
||||
// If not separate texture or sampler, don't bother.
|
||||
if (!separate_image && !separate_sampler)
|
||||
return true;
|
||||
|
||||
uint32_t id = args[1];
|
||||
uint32_t ptr = args[2];
|
||||
compiler.set<SPIRExpression>(id, "", result_type, true);
|
||||
compiler.register_read(id, ptr, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
case OpInBoundsAccessChain:
|
||||
case OpAccessChain:
|
||||
{
|
||||
if (length < 3)
|
||||
return false;
|
||||
|
||||
// Technically, it is possible to have arrays of textures and arrays of samplers and combine them, but this becomes essentially
|
||||
// impossible to implement, since we don't know which concrete sampler we are accessing.
|
||||
// One potential way is to create a combinatorial explosion where N textures and M samplers are combined into N * M sampler2Ds,
|
||||
// but this seems ridiculously complicated for a problem which is easy to work around.
|
||||
// Checking access chains like this assumes we don't have samplers or textures inside uniform structs, but this makes no sense.
|
||||
|
||||
auto &type = compiler.get<SPIRType>(args[0]);
|
||||
bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
|
||||
bool separate_sampler = type.basetype == SPIRType::Sampler;
|
||||
if (separate_image)
|
||||
throw CompilerError(
|
||||
"Attempting to use arrays of separate images. This is not possible to statically remap to plain GLSL.");
|
||||
if (separate_sampler)
|
||||
throw CompilerError("Attempting to use arrays of separate samplers. This is not possible to statically "
|
||||
"remap to plain GLSL.");
|
||||
return true;
|
||||
}
|
||||
|
||||
case OpSampledImage:
|
||||
// Do it outside.
|
||||
break;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (length < 4)
|
||||
return false;
|
||||
|
||||
auto *image = compiler.maybe_get_backing_variable(args[2]);
|
||||
auto *sampler = compiler.maybe_get_backing_variable(args[3]);
|
||||
auto image_id = image ? image->self : args[2];
|
||||
auto sampler_id = sampler ? sampler->self : args[3];
|
||||
|
||||
// FIXME: For function calls, we need to remap IDs which are function parameters into global variables.
|
||||
// This information is statically known from the current place in the call stack.
|
||||
// For now, we only look directly at global variables.
|
||||
// Function parameters are not necessarily pointers, so if we don't have a backing variable, remapping will know
|
||||
// which backing variable the image/sample came from.
|
||||
auto itr = find_if(begin(compiler.combined_image_samplers), end(compiler.combined_image_samplers),
|
||||
[image_id, sampler_id](const CombinedImageSampler &combined) {
|
||||
return combined.image_id == image_id && combined.sampler_id == sampler_id;
|
||||
});
|
||||
|
||||
if (itr == end(compiler.combined_image_samplers))
|
||||
{
|
||||
auto id = compiler.increase_bound_by(2);
|
||||
auto type_id = id + 0;
|
||||
auto combined_id = id + 1;
|
||||
auto sampled_type = args[0];
|
||||
|
||||
// Make a new type, pointer to OpTypeSampledImage, so we can make a variable of this type.
|
||||
// We will probably have this type lying around, but it doesn't hurt to make duplicates for internal purposes.
|
||||
auto &type = compiler.set<SPIRType>(type_id);
|
||||
auto &base = compiler.get<SPIRType>(sampled_type);
|
||||
type = base;
|
||||
type.pointer = true;
|
||||
type.storage = StorageClassUniformConstant;
|
||||
|
||||
// Build new variable.
|
||||
compiler.set<SPIRVariable>(combined_id, sampled_type, StorageClassUniformConstant, 0);
|
||||
compiler.combined_image_samplers.push_back({ combined_id, image_id, sampler_id });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Compiler::build_combined_image_samplers()
|
||||
{
|
||||
combined_image_samplers.clear();
|
||||
CombinedImageSamplerHandler handler(*this);
|
||||
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
|
||||
}
|
||||
|
|
|
@ -477,6 +477,17 @@ private:
|
|||
std::unordered_set<uint32_t> &variables;
|
||||
};
|
||||
|
||||
struct CombinedImageSamplerHandler : OpcodeHandler
|
||||
{
|
||||
CombinedImageSamplerHandler(Compiler &compiler_)
|
||||
: compiler(compiler_)
|
||||
{
|
||||
}
|
||||
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
|
||||
|
||||
Compiler &compiler;
|
||||
};
|
||||
|
||||
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
|
||||
bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
|
||||
// This must be an ordered data structure so we always pick the same type aliases.
|
||||
|
|
|
@ -1866,7 +1866,33 @@ void CompilerGLSL::emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left,
|
|||
|
||||
void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
|
||||
{
|
||||
emit_binary_func_op(result_type, result_id, image_id, samp_id, type_to_glsl(get<SPIRType>(result_type)).c_str());
|
||||
if (options.vulkan_semantics)
|
||||
emit_binary_func_op(result_type, result_id, image_id, samp_id,
|
||||
type_to_glsl(get<SPIRType>(result_type)).c_str());
|
||||
else
|
||||
{
|
||||
// For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
|
||||
// all possible combinations into new sampler2D uniforms.
|
||||
auto *image = maybe_get_backing_variable(image_id);
|
||||
auto *samp = maybe_get_backing_variable(samp_id);
|
||||
if (image)
|
||||
image_id = image->self;
|
||||
if (samp)
|
||||
samp_id = samp->self;
|
||||
|
||||
// FIXME: This must be context-dependent.
|
||||
auto &mapping = combined_image_samplers;
|
||||
|
||||
auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
|
||||
return combined.image_id == image_id && combined.sampler_id == samp_id;
|
||||
});
|
||||
|
||||
if (itr != end(combined_image_samplers))
|
||||
emit_op(result_type, result_id, to_expression(itr->combined_id), true, false);
|
||||
else
|
||||
throw CompilerError("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
|
||||
"before compile() was called?");
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_texture_op(const Instruction &i)
|
||||
|
|
Загрузка…
Ссылка в новой задаче