GPUShaderCreateInfo: Merge changes from eevee-rewrite
This includes multiple commits: - Fix crash when using std::cerr for error output - Add auto_resource_location which overrides all resources location (not vert input) - Improve codestyle of error reporting. - Add type conversion to string and to `eGPUType` - Add comparison operator (will be used for hash collision resolution). - Add members related to generated code (codegen)
This commit is contained in:
@@ -62,11 +62,6 @@ void ShaderCreateInfo::finalize()
|
||||
/* Recursive. */
|
||||
const_cast<ShaderCreateInfo &>(info).finalize();
|
||||
|
||||
#if 0 /* Enabled for debugging merging. TODO(fclem) exception handling and error reporting in \
|
||||
console. */
|
||||
std::cout << "Merging : " << info_name << " > " << name_ << std::endl;
|
||||
#endif
|
||||
|
||||
interface_names_size_ += info.interface_names_size_;
|
||||
|
||||
vertex_inputs_.extend(info.vertex_inputs_);
|
||||
@@ -83,37 +78,72 @@ void ShaderCreateInfo::finalize()
|
||||
|
||||
validate(info);
|
||||
|
||||
auto assert_no_overlap = [&](const bool test, const StringRefNull error) {
|
||||
if (!test) {
|
||||
std::cout << name_ << ": Validation failed while merging " << info.name_ << " : ";
|
||||
std::cout << error << std::endl;
|
||||
BLI_assert(0);
|
||||
}
|
||||
};
|
||||
|
||||
if (info.compute_layout_.local_size_x != -1) {
|
||||
compute_layout_.local_size_x = info.compute_layout_.local_size_x;
|
||||
compute_layout_.local_size_y = info.compute_layout_.local_size_y;
|
||||
compute_layout_.local_size_z = info.compute_layout_.local_size_z;
|
||||
assert_no_overlap(compute_layout_.local_size_x == -1, "Compute layout already defined");
|
||||
compute_layout_ = info.compute_layout_;
|
||||
}
|
||||
|
||||
if (!info.vertex_source_.is_empty()) {
|
||||
BLI_assert(vertex_source_.is_empty());
|
||||
assert_no_overlap(vertex_source_.is_empty(), "Vertex source already existing");
|
||||
vertex_source_ = info.vertex_source_;
|
||||
}
|
||||
if (!info.geometry_source_.is_empty()) {
|
||||
BLI_assert(geometry_source_.is_empty());
|
||||
assert_no_overlap(geometry_source_.is_empty(), "Geometry source already existing");
|
||||
geometry_source_ = info.geometry_source_;
|
||||
geometry_layout_ = info.geometry_layout_;
|
||||
}
|
||||
if (!info.fragment_source_.is_empty()) {
|
||||
BLI_assert(fragment_source_.is_empty());
|
||||
assert_no_overlap(fragment_source_.is_empty(), "Fragment source already existing");
|
||||
fragment_source_ = info.fragment_source_;
|
||||
}
|
||||
if (!info.compute_source_.is_empty()) {
|
||||
BLI_assert(compute_source_.is_empty());
|
||||
assert_no_overlap(compute_source_.is_empty(), "Compute source already existing");
|
||||
compute_source_ = info.compute_source_;
|
||||
}
|
||||
|
||||
do_static_compilation_ = do_static_compilation_ || info.do_static_compilation_;
|
||||
}
|
||||
|
||||
if (auto_resource_location_) {
|
||||
int images = 0, samplers = 0, ubos = 0, ssbos = 0;
|
||||
|
||||
auto set_resource_slot = [&](Resource &res) {
|
||||
switch (res.bind_type) {
|
||||
case Resource::BindType::UNIFORM_BUFFER:
|
||||
res.slot = ubos++;
|
||||
break;
|
||||
case Resource::BindType::STORAGE_BUFFER:
|
||||
res.slot = ssbos++;
|
||||
break;
|
||||
case Resource::BindType::SAMPLER:
|
||||
res.slot = samplers++;
|
||||
break;
|
||||
case Resource::BindType::IMAGE:
|
||||
res.slot = images++;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &res : batch_resources_) {
|
||||
set_resource_slot(res);
|
||||
}
|
||||
for (auto &res : pass_resources_) {
|
||||
set_resource_slot(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info)
|
||||
{
|
||||
{
|
||||
if (!auto_resource_location_) {
|
||||
/* Check same bind-points usage in OGL. */
|
||||
Set<int> images, samplers, ubos, ssbos;
|
||||
|
||||
@@ -133,26 +163,26 @@ void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info)
|
||||
};
|
||||
|
||||
auto print_error_msg = [&](const Resource &res) {
|
||||
std::cerr << name_ << ": Validation failed : Overlapping ";
|
||||
std::cout << name_ << ": Validation failed : Overlapping ";
|
||||
|
||||
switch (res.bind_type) {
|
||||
case Resource::BindType::UNIFORM_BUFFER:
|
||||
std::cerr << "Uniform Buffer " << res.uniformbuf.name;
|
||||
std::cout << "Uniform Buffer " << res.uniformbuf.name;
|
||||
break;
|
||||
case Resource::BindType::STORAGE_BUFFER:
|
||||
std::cerr << "Storage Buffer " << res.storagebuf.name;
|
||||
std::cout << "Storage Buffer " << res.storagebuf.name;
|
||||
break;
|
||||
case Resource::BindType::SAMPLER:
|
||||
std::cerr << "Sampler " << res.sampler.name;
|
||||
std::cout << "Sampler " << res.sampler.name;
|
||||
break;
|
||||
case Resource::BindType::IMAGE:
|
||||
std::cerr << "Image " << res.image.name;
|
||||
std::cout << "Image " << res.image.name;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unknown Type";
|
||||
std::cout << "Unknown Type";
|
||||
break;
|
||||
}
|
||||
std::cerr << " (" << res.slot << ") while merging " << other_info.name_ << std::endl;
|
||||
std::cout << " (" << res.slot << ") while merging " << other_info.name_ << std::endl;
|
||||
};
|
||||
|
||||
for (auto &res : batch_resources_) {
|
||||
|
||||
@@ -30,8 +30,11 @@
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace blender::gpu::shader {
|
||||
|
||||
#ifndef GPU_SHADER_CREATE_INFO
|
||||
@@ -62,6 +65,59 @@ enum class Type {
|
||||
BOOL,
|
||||
};
|
||||
|
||||
/* All of these functions is a bit out of place */
|
||||
static inline Type to_type(const eGPUType type)
|
||||
{
|
||||
switch (type) {
|
||||
case GPU_FLOAT:
|
||||
return Type::FLOAT;
|
||||
case GPU_VEC2:
|
||||
return Type::VEC2;
|
||||
case GPU_VEC3:
|
||||
return Type::VEC3;
|
||||
case GPU_VEC4:
|
||||
return Type::VEC4;
|
||||
case GPU_MAT3:
|
||||
return Type::MAT3;
|
||||
case GPU_MAT4:
|
||||
return Type::MAT4;
|
||||
default:
|
||||
BLI_assert_msg(0, "Error: Cannot convert eGPUType to shader::Type.");
|
||||
return Type::FLOAT;
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::ostream &operator<<(std::ostream &stream, const Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Type::FLOAT:
|
||||
return stream << "float";
|
||||
case Type::VEC2:
|
||||
return stream << "vec2";
|
||||
case Type::VEC3:
|
||||
return stream << "vec3";
|
||||
case Type::VEC4:
|
||||
return stream << "vec4";
|
||||
case Type::MAT3:
|
||||
return stream << "mat3";
|
||||
case Type::MAT4:
|
||||
return stream << "mat4";
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::ostream &operator<<(std::ostream &stream, const eGPUType type)
|
||||
{
|
||||
switch (type) {
|
||||
case GPU_CLOSURE:
|
||||
return stream << "Closure";
|
||||
default:
|
||||
return stream << to_type(type);
|
||||
}
|
||||
}
|
||||
|
||||
enum class BuiltinBits {
|
||||
NONE = 0,
|
||||
/**
|
||||
@@ -229,6 +285,8 @@ struct ShaderCreateInfo {
|
||||
bool do_static_compilation_ = false;
|
||||
/** If true, all additionally linked create info will be merged into this one. */
|
||||
bool finalized_ = false;
|
||||
/** If true, all resources will have an automatic location assigned. */
|
||||
bool auto_resource_location_ = false;
|
||||
/**
|
||||
* Maximum length of all the resource names including each null terminator.
|
||||
* Only for names used by gpu::ShaderInterface.
|
||||
@@ -236,11 +294,36 @@ struct ShaderCreateInfo {
|
||||
size_t interface_names_size_ = 0;
|
||||
/** Manually set builtins. */
|
||||
BuiltinBits builtins_ = BuiltinBits::NONE;
|
||||
/** Manually set generated code. */
|
||||
std::string vertex_source_generated = "";
|
||||
std::string fragment_source_generated = "";
|
||||
std::string typedef_source_generated = "";
|
||||
/** Manually set generated dependencies. */
|
||||
Vector<const char *, 0> dependencies_generated;
|
||||
|
||||
#define TEST_EQUAL(a, b, _member) \
|
||||
if (!((a)._member == (b)._member)) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define TEST_VECTOR_EQUAL(a, b, _vector) \
|
||||
TEST_EQUAL(a, b, _vector.size()); \
|
||||
for (auto i : _vector.index_range()) { \
|
||||
TEST_EQUAL(a, b, _vector[i]); \
|
||||
}
|
||||
|
||||
struct VertIn {
|
||||
int index;
|
||||
Type type;
|
||||
StringRefNull name;
|
||||
|
||||
bool operator==(const VertIn &b)
|
||||
{
|
||||
TEST_EQUAL(*this, b, index);
|
||||
TEST_EQUAL(*this, b, type);
|
||||
TEST_EQUAL(*this, b, name);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Vector<VertIn> vertex_inputs_;
|
||||
|
||||
@@ -250,6 +333,15 @@ struct ShaderCreateInfo {
|
||||
PrimitiveOut primitive_out;
|
||||
/** Set to -1 by default to check if used. */
|
||||
int max_vertices = -1;
|
||||
|
||||
bool operator==(const GeometryStageLayout &b)
|
||||
{
|
||||
TEST_EQUAL(*this, b, primitive_in);
|
||||
TEST_EQUAL(*this, b, invocations);
|
||||
TEST_EQUAL(*this, b, primitive_out);
|
||||
TEST_EQUAL(*this, b, max_vertices);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
GeometryStageLayout geometry_layout_;
|
||||
|
||||
@@ -257,8 +349,15 @@ struct ShaderCreateInfo {
|
||||
int local_size_x = -1;
|
||||
int local_size_y = -1;
|
||||
int local_size_z = -1;
|
||||
};
|
||||
|
||||
bool operator==(const ComputeStageLayout &b)
|
||||
{
|
||||
TEST_EQUAL(*this, b, local_size_x);
|
||||
TEST_EQUAL(*this, b, local_size_y);
|
||||
TEST_EQUAL(*this, b, local_size_z);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
ComputeStageLayout compute_layout_;
|
||||
|
||||
struct FragOut {
|
||||
@@ -266,6 +365,15 @@ struct ShaderCreateInfo {
|
||||
Type type;
|
||||
DualBlend blend;
|
||||
StringRefNull name;
|
||||
|
||||
bool operator==(const FragOut &b)
|
||||
{
|
||||
TEST_EQUAL(*this, b, index);
|
||||
TEST_EQUAL(*this, b, type);
|
||||
TEST_EQUAL(*this, b, blend);
|
||||
TEST_EQUAL(*this, b, name);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Vector<FragOut> fragment_outputs_;
|
||||
|
||||
@@ -311,6 +419,35 @@ struct ShaderCreateInfo {
|
||||
};
|
||||
|
||||
Resource(BindType type, int _slot) : bind_type(type), slot(_slot){};
|
||||
|
||||
bool operator==(const Resource &b)
|
||||
{
|
||||
TEST_EQUAL(*this, b, bind_type);
|
||||
TEST_EQUAL(*this, b, slot);
|
||||
switch (bind_type) {
|
||||
case UNIFORM_BUFFER:
|
||||
TEST_EQUAL(*this, b, uniformbuf.type_name);
|
||||
TEST_EQUAL(*this, b, uniformbuf.name);
|
||||
break;
|
||||
case STORAGE_BUFFER:
|
||||
TEST_EQUAL(*this, b, storagebuf.qualifiers);
|
||||
TEST_EQUAL(*this, b, storagebuf.type_name);
|
||||
TEST_EQUAL(*this, b, storagebuf.name);
|
||||
break;
|
||||
case SAMPLER:
|
||||
TEST_EQUAL(*this, b, sampler.type);
|
||||
TEST_EQUAL(*this, b, sampler.sampler);
|
||||
TEST_EQUAL(*this, b, sampler.name);
|
||||
break;
|
||||
case IMAGE:
|
||||
TEST_EQUAL(*this, b, image.format);
|
||||
TEST_EQUAL(*this, b, image.type);
|
||||
TEST_EQUAL(*this, b, image.qualifiers);
|
||||
TEST_EQUAL(*this, b, image.name);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Resources are grouped by frequency of change.
|
||||
@@ -327,6 +464,14 @@ struct ShaderCreateInfo {
|
||||
Type type;
|
||||
StringRefNull name;
|
||||
int array_size;
|
||||
|
||||
bool operator==(const PushConst &b)
|
||||
{
|
||||
TEST_EQUAL(*this, b, type);
|
||||
TEST_EQUAL(*this, b, name);
|
||||
TEST_EQUAL(*this, b, array_size);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Vector<PushConst> push_constants_;
|
||||
@@ -554,6 +699,12 @@ struct ShaderCreateInfo {
|
||||
return *(Self *)this;
|
||||
}
|
||||
|
||||
Self &auto_resource_location(bool value)
|
||||
{
|
||||
auto_resource_location_ = value;
|
||||
return *(Self *)this;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -624,6 +775,77 @@ struct ShaderCreateInfo {
|
||||
void validate(const ShaderCreateInfo &other_info);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Operators.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/* Comparison operator for GPUPass cache. We only compare if it will create the same shader code.
|
||||
* So we do not compare name and some other internal stuff. */
|
||||
bool operator==(const ShaderCreateInfo &b)
|
||||
{
|
||||
TEST_EQUAL(*this, b, builtins_);
|
||||
TEST_EQUAL(*this, b, vertex_source_generated);
|
||||
TEST_EQUAL(*this, b, fragment_source_generated);
|
||||
TEST_EQUAL(*this, b, typedef_source_generated);
|
||||
TEST_VECTOR_EQUAL(*this, b, vertex_inputs_);
|
||||
TEST_EQUAL(*this, b, geometry_layout_);
|
||||
TEST_EQUAL(*this, b, compute_layout_);
|
||||
TEST_VECTOR_EQUAL(*this, b, fragment_outputs_);
|
||||
TEST_VECTOR_EQUAL(*this, b, pass_resources_);
|
||||
TEST_VECTOR_EQUAL(*this, b, batch_resources_);
|
||||
TEST_VECTOR_EQUAL(*this, b, vertex_out_interfaces_);
|
||||
TEST_VECTOR_EQUAL(*this, b, geometry_out_interfaces_);
|
||||
TEST_VECTOR_EQUAL(*this, b, push_constants_);
|
||||
TEST_VECTOR_EQUAL(*this, b, typedef_sources_);
|
||||
TEST_EQUAL(*this, b, vertex_source_);
|
||||
TEST_EQUAL(*this, b, geometry_source_);
|
||||
TEST_EQUAL(*this, b, fragment_source_);
|
||||
TEST_EQUAL(*this, b, compute_source_);
|
||||
TEST_VECTOR_EQUAL(*this, b, additional_infos_);
|
||||
TEST_VECTOR_EQUAL(*this, b, defines_);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Debug print */
|
||||
friend std::ostream &operator<<(std::ostream &stream, const ShaderCreateInfo &info)
|
||||
{
|
||||
/* TODO(@fclem): Complete print. */
|
||||
|
||||
auto print_resource = [&](const Resource &res) {
|
||||
switch (res.bind_type) {
|
||||
case Resource::BindType::UNIFORM_BUFFER:
|
||||
stream << "UNIFORM_BUFFER(" << res.slot << ", " << res.uniformbuf.name << ")"
|
||||
<< std::endl;
|
||||
break;
|
||||
case Resource::BindType::STORAGE_BUFFER:
|
||||
stream << "STORAGE_BUFFER(" << res.slot << ", " << res.storagebuf.name << ")"
|
||||
<< std::endl;
|
||||
break;
|
||||
case Resource::BindType::SAMPLER:
|
||||
stream << "SAMPLER(" << res.slot << ", " << res.sampler.name << ")" << std::endl;
|
||||
break;
|
||||
case Resource::BindType::IMAGE:
|
||||
stream << "IMAGE(" << res.slot << ", " << res.image.name << ")" << std::endl;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/* TODO(@fclem): Order the resources. */
|
||||
for (auto &res : info.batch_resources_) {
|
||||
print_resource(res);
|
||||
}
|
||||
for (auto &res : info.pass_resources_) {
|
||||
print_resource(res);
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
#undef TEST_EQUAL
|
||||
#undef TEST_VECTOR_EQUAL
|
||||
};
|
||||
|
||||
} // namespace blender::gpu::shader
|
||||
|
||||
Reference in New Issue
Block a user