Begin implementing parameter remapping for combined image sampler.

The basic idea here is that all functions will have a list of which
combinations of parameters will be combined inside the function.
The caller will then know which combined samplers must be provided to
the callee in order to satisfy it.
This commit is contained in:
Hans-Kristian Arntzen 2016-09-11 11:39:20 +02:00
parent 901b45e09a
commit ed98a8ec86
3 changed files with 116 additions and 4 deletions

View File

@ -439,12 +439,28 @@ struct SPIRFunction : IVariant
uint32_t write_count;
};
// When calling a function, and we're remapping separate image samplers,
// resolve these arguments into combined image samplers and pass them
// as additional arguments in this order.
// It gets more complicated as functions can pull in their own globals
// and combine them with parameters,
// so we need to distinguish if something is local parameter index
// or a global ID.
struct CombinedImageSamplerParameter
{
uint32_t texture_id;
uint32_t sampler_id;
bool global_texture;
bool global_sampler;
};
uint32_t return_type;
uint32_t function_type;
std::vector<Parameter> arguments;
std::vector<uint32_t> local_variables;
uint32_t entry_block = 0;
std::vector<uint32_t> blocks;
std::vector<CombinedImageSamplerParameter> combined_parameters;
void add_local_variable(uint32_t id)
{
@ -459,6 +475,7 @@ struct SPIRFunction : IVariant
bool active = false;
bool flush_undeclared = true;
bool do_combined_parameters = true;
};
struct SPIRVariable : IVariant

View File

@ -1927,7 +1927,7 @@ bool Compiler::traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHand
return false;
if (!traverse_all_reachable_opcodes(get<SPIRFunction>(ops[2]), handler))
return false;
if (!handler.end_function_scope())
if (!handler.end_function_scope(ops, i.length))
return false;
}
}
@ -2348,15 +2348,98 @@ bool Compiler::CombinedImageSamplerHandler::begin_function_scope(const uint32_t
args += 3;
length -= 3;
push_remap_parameters(callee, args, length);
functions.push(&callee);
return true;
}
bool Compiler::CombinedImageSamplerHandler::end_function_scope()
bool Compiler::CombinedImageSamplerHandler::end_function_scope(const uint32_t *args, uint32_t length)
{
if (length < 3)
return false;
auto &callee = compiler.get<SPIRFunction>(args[2]);
args += 3;
length -= 3;
// There are two types of cases we have to handle,
// a callee might call sampler2D(texture2D, sampler) directly where
// one or more parameters originate from parameters.
// Alternatively, we need to provide combined image samplers to our callees,
// and in this case we need to add those as well.
pop_remap_parameters();
// Our callee has now been processed at least once.
// No point in doing it again.
callee.do_combined_parameters = false;
auto &params = functions.top()->combined_parameters;
functions.pop();
if (functions.empty())
return true;
auto &caller = *functions.top();
if (caller.do_combined_parameters)
{
for (auto &param : params)
{
uint32_t texture_id = param.global_texture ? param.texture_id : args[param.texture_id];
uint32_t sampler_id = param.global_sampler ? param.sampler_id : args[param.sampler_id];
auto *t = compiler.maybe_get_backing_variable(texture_id);
auto *s = compiler.maybe_get_backing_variable(sampler_id);
if (t)
texture_id = t->self;
if (s)
sampler_id = s->self;
register_combined_image_sampler(caller, texture_id, sampler_id);
}
}
return true;
}
void Compiler::CombinedImageSamplerHandler::register_combined_image_sampler(SPIRFunction &caller, uint32_t texture_id,
uint32_t sampler_id)
{
// We now have a texture ID and a sampler ID which will either be found as a global
// or a parameter in our own function. If both are global, they will not need a parameter,
// otherwise, add it to our list.
SPIRFunction::CombinedImageSamplerParameter param = {
texture_id, sampler_id, true, true,
};
auto texture_itr = find_if(begin(caller.arguments), end(caller.arguments),
[texture_id](const SPIRFunction::Parameter &p) { return p.id == texture_id; });
auto sampler_itr = find_if(begin(caller.arguments), end(caller.arguments),
[sampler_id](const SPIRFunction::Parameter &p) { return p.id == sampler_id; });
if (texture_itr != end(caller.arguments))
{
param.global_texture = false;
param.texture_id = texture_itr - begin(caller.arguments);
}
if (sampler_itr != end(caller.arguments))
{
param.global_sampler = false;
param.sampler_id = sampler_itr - begin(caller.arguments);
}
if (param.global_texture && param.global_sampler)
return;
auto itr = find_if(begin(caller.combined_parameters), end(caller.combined_parameters),
[&param](const SPIRFunction::CombinedImageSamplerParameter &p) {
return param.texture_id == p.texture_id && param.sampler_id == p.sampler_id &&
param.global_texture == p.global_texture && param.global_sampler == p.global_sampler;
});
if (itr == end(caller.combined_parameters))
caller.combined_parameters.push_back(param);
}
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.
@ -2463,6 +2546,16 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar
void Compiler::build_combined_image_samplers()
{
for (auto &id : ids)
{
if (id.get_type() == TypeFunction)
{
auto &func = id.get<SPIRFunction>();
func.combined_parameters.clear();
func.do_combined_parameters = true;
}
}
combined_image_samplers.clear();
CombinedImageSamplerHandler handler(*this);
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);

View File

@ -450,7 +450,7 @@ private:
return true;
}
virtual bool end_function_scope()
virtual bool end_function_scope(const uint32_t *, uint32_t)
{
return true;
}
@ -496,16 +496,18 @@ private:
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
bool begin_function_scope(const uint32_t *args, uint32_t length) override;
bool end_function_scope() override;
bool end_function_scope(const uint32_t *args, uint32_t length) override;
Compiler &compiler;
// Each function in the call stack needs its own remapping for parameters so we can deduce which global variable each texture/sampler the parameter is statically bound to.
std::stack<std::unordered_map<uint32_t, uint32_t>> parameter_remapping;
std::stack<SPIRFunction *> functions;
uint32_t remap_parameter(uint32_t id);
void push_remap_parameters(const SPIRFunction &func, const uint32_t *args, uint32_t length);
void pop_remap_parameters();
void register_combined_image_sampler(SPIRFunction &caller, uint32_t texture_id, uint32_t sampler_id);
};
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;