Cleanup: GPU: Remove unused Transform Feedback implementation

Most of the cleanup is inside the metal backend.

Pull Request: https://projects.blender.org/blender/blender/pulls/134349
This commit is contained in:
Clément Foucault
2025-02-10 17:30:42 +01:00
committed by Clément Foucault
parent 1a62fdc82a
commit 86b70143d5
26 changed files with 55 additions and 553 deletions

View File

@@ -824,12 +824,11 @@ static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCach
GPUVertFormat format = {0};
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
/* Transform feedback buffer only needs to be resident in device memory. */
GPUUsageType type = GPU_transform_feedback_support() ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_STATIC;
/* Procedural Subdiv buffer only needs to be resident in device memory. */
cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format_ex(
format, type | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
format, GPU_USAGE_DEVICE_ONLY | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
/* Create a destination buffer for the transform feedback. Sized appropriately */
/* Create a destination buffer for the procedural Subdiv. Sized appropriately */
/* Those are points! not line segments. */
uint point_len = cache->final[subdiv].strands_res * cache->strands_len;
/* Avoid creating null sized VBO which can lead to crashes on certain platforms. */

View File

@@ -69,7 +69,6 @@ void GPU_mem_stats_get(int *r_totalmem, int *r_freemem);
bool GPU_stereo_quadbuffer_support();
int GPU_minimum_per_vertex_stride();
bool GPU_transform_feedback_support();
/** WARNING: Should only be called at startup from creator_args. Never call it at runtime. */
void GPU_compilation_subprocess_override_set(int count);

View File

@@ -268,13 +268,6 @@ bool GPU_shader_batch_specializations_is_ready(SpecializationBatchHandle &handle
* All of this section is deprecated and should be ported to use the API described above.
* \{ */
enum eGPUShaderTFBType {
GPU_SHADER_TFB_NONE = 0, /* Transform feedback unsupported. */
GPU_SHADER_TFB_POINTS = 1,
GPU_SHADER_TFB_LINES = 2,
GPU_SHADER_TFB_TRIANGLES = 3,
};
GPUShader *GPU_shader_create(std::optional<blender::StringRefNull> vertcode,
std::optional<blender::StringRefNull> fragcode,
std::optional<blender::StringRefNull> geomcode,
@@ -297,17 +290,8 @@ GPUShader *GPU_shader_create_ex(std::optional<blender::StringRefNull> vertcode,
std::optional<blender::StringRefNull> computecode,
std::optional<blender::StringRefNull> libcode,
std::optional<blender::StringRefNull> defines,
eGPUShaderTFBType tf_type,
const char **tf_names,
int tf_count,
blender::StringRefNull shname);
/**
* Returns true if transform feedback was successfully enabled.
*/
bool GPU_shader_transform_feedback_enable(GPUShader *shader, blender::gpu::VertBuf *vertbuf);
void GPU_shader_transform_feedback_disable(GPUShader *shader);
/**
* Shader cache warming.
* For each shader, rendering APIs perform a two-step compilation:

View File

@@ -212,11 +212,6 @@ int GPU_minimum_per_vertex_stride()
return GCaps.minimum_per_vertex_stride;
}
bool GPU_transform_feedback_support()
{
return GCaps.transform_feedback_support;
}
size_t GPU_max_storage_buffer_size()
{
return GCaps.max_storage_buffer_size;

View File

@@ -47,7 +47,6 @@ struct GPUCapabilities {
bool mem_stats_support = false;
bool geometry_shader_support = false;
bool shader_draw_parameters_support = false;
bool transform_feedback_support = false;
bool hdr_viewport_support = false;
bool texture_view_support = true;
bool stencil_export_support = false;

View File

@@ -121,9 +121,6 @@ GPUShader *GPU_shader_create_ex(const std::optional<StringRefNull> vertcode,
const std::optional<StringRefNull> computecode,
const std::optional<StringRefNull> libcode,
const std::optional<StringRefNull> defines,
const eGPUShaderTFBType tf_type,
const char **tf_names,
const int tf_count,
const StringRefNull shname)
{
/* At least a vertex shader and a fragment shader are required, or only a compute shader. */
@@ -195,11 +192,6 @@ GPUShader *GPU_shader_create_ex(const std::optional<StringRefNull> vertcode,
shader->compute_shader_from_glsl(sources);
}
if (tf_names != nullptr && tf_count > 0) {
BLI_assert(tf_type != GPU_SHADER_TFB_NONE);
shader->transform_feedback_names_set(Span<const char *>(tf_names, tf_count), tf_type);
}
if (!shader->finalize()) {
delete shader;
return nullptr;
@@ -226,16 +218,8 @@ GPUShader *GPU_shader_create(const std::optional<StringRefNull> vertcode,
const std::optional<StringRefNull> defines,
const StringRefNull shname)
{
return GPU_shader_create_ex(vertcode,
fragcode,
geomcode,
std::nullopt,
libcode,
defines,
GPU_SHADER_TFB_NONE,
nullptr,
0,
shname);
return GPU_shader_create_ex(
vertcode, fragcode, geomcode, std::nullopt, libcode, defines, shname);
}
GPUShader *GPU_shader_create_compute(const std::optional<StringRefNull> computecode,
@@ -243,16 +227,8 @@ GPUShader *GPU_shader_create_compute(const std::optional<StringRefNull> computec
const std::optional<StringRefNull> defines,
const StringRefNull shname)
{
return GPU_shader_create_ex(std::nullopt,
std::nullopt,
std::nullopt,
computecode,
libcode,
defines,
GPU_SHADER_TFB_NONE,
nullptr,
0,
shname);
return GPU_shader_create_ex(
std::nullopt, std::nullopt, std::nullopt, computecode, libcode, defines, shname);
}
const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name)
@@ -378,16 +354,8 @@ GPUShader *GPU_shader_create_from_python(std::optional<StringRefNull> vertcode,
/* Use pyGPUShader as default name for shader. */
blender::StringRefNull shname = name.value_or("pyGPUShader");
GPUShader *sh = GPU_shader_create_ex(vertcode,
fragcode,
geomcode,
std::nullopt,
libcode,
defines,
GPU_SHADER_TFB_NONE,
nullptr,
0,
shname);
GPUShader *sh = GPU_shader_create_ex(
vertcode, fragcode, geomcode, std::nullopt, libcode, defines, shname);
return sh;
}
@@ -515,24 +483,6 @@ void GPU_shader_warm_cache(GPUShader *shader, int limit)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform feedback
*
* TODO(fclem): Should be replaced by compute shaders.
* \{ */
bool GPU_shader_transform_feedback_enable(GPUShader *shader, blender::gpu::VertBuf *vertbuf)
{
return unwrap(shader)->transform_feedback_enable(vertbuf);
}
void GPU_shader_transform_feedback_disable(GPUShader *shader)
{
unwrap(shader)->transform_feedback_disable();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Assign specialization constants.
* \{ */
@@ -1000,10 +950,6 @@ Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_ba
shader->compute_shader_from_glsl(sources);
}
if (info.tf_type_ != GPU_SHADER_TFB_NONE && info.tf_names_.size() > 0) {
shader->transform_feedback_names_set(info.tf_names_.as_span(), info.tf_type_);
}
if (!shader->finalize(&info)) {
delete shader;
GPU_debug_group_end();

View File

@@ -250,7 +250,7 @@ std::string ShaderCreateInfo::check_error() const
if (this->vertex_source_.is_empty()) {
error += "Missing vertex shader in " + this->name_ + ".\n";
}
if (tf_type_ == GPU_SHADER_TFB_NONE && this->fragment_source_.is_empty()) {
if (this->fragment_source_.is_empty()) {
error += "Missing fragment shader in " + this->name_ + ".\n";
}
}
@@ -563,8 +563,7 @@ bool gpu_shader_create_info_compile(const char *name_starts_with_filter)
continue;
}
if ((info->metal_backend_only_ && GPU_backend_get_type() != GPU_BACKEND_METAL) ||
(GPU_geometry_shader_support() == false && info->geometry_source_ != nullptr) ||
(GPU_transform_feedback_support() == false && info->tf_type_ != GPU_SHADER_TFB_NONE))
(GPU_geometry_shader_support() == false && info->geometry_source_ != nullptr))
{
skipped++;
continue;

View File

@@ -885,10 +885,6 @@ struct ShaderCreateInfo {
*/
Vector<StringRefNull> additional_infos_;
/* Transform feedback properties. */
eGPUShaderTFBType tf_type_ = GPU_SHADER_TFB_NONE;
Vector<const char *> tf_names_;
/* Api-specific parameters. */
# ifdef WITH_METAL_BACKEND
ushort mtl_max_threads_per_threadgroup_ = 0;
@@ -1258,27 +1254,6 @@ struct ShaderCreateInfo {
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform feedback properties
*
* Transform feedback enablement and output binding assignment.
* \{ */
Self &transform_feedback_mode(eGPUShaderTFBType tf_mode)
{
BLI_assert(tf_mode != GPU_SHADER_TFB_NONE);
tf_type_ = tf_mode;
return *(Self *)this;
}
Self &transform_feedback_output_name(const char *name)
{
BLI_assert(tf_type_ != GPU_SHADER_TFB_NONE);
tf_names_.append(name);
return *(Self *)this;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name API-Specific Parameters
*

View File

@@ -25,7 +25,7 @@ class GPULogParser;
class Context;
/* Set to 1 to log the full source of shaders that fail to compile. */
#define DEBUG_LOG_SHADER_SRC_ON_ERROR 0
#define DEBUG_LOG_SHADER_SRC_ON_ERROR 1
/**
* Compilation is done on a list of GLSL sources. This list contains placeholders that should be
@@ -98,11 +98,6 @@ class Shader {
* See `GPU_shader_warm_cache(..)` in `GPU_shader.hh` for more information. */
virtual void warm_cache(int limit) = 0;
virtual void transform_feedback_names_set(Span<const char *> name_list,
eGPUShaderTFBType geom_type) = 0;
virtual bool transform_feedback_enable(VertBuf *) = 0;
virtual void transform_feedback_disable() = 0;
virtual void bind() = 0;
virtual void unbind() = 0;

View File

@@ -522,7 +522,6 @@ void MTLBackend::capabilities_init(MTLContext *ctx)
GCaps.max_work_group_size[1] = max_threads_per_threadgroup_per_dim;
GCaps.max_work_group_size[2] = max_threads_per_threadgroup_per_dim;
GCaps.transform_feedback_support = true;
GCaps.stencil_export_support = true;
/* OPENGL Related workarounds -- none needed for Metal. */

View File

@@ -20,9 +20,8 @@ namespace blender::gpu {
/* Total maximum buffers which can be bound to an encoder, for use within a shader.
* Uniform buffers and storage buffers share the set of available bind buffers.
* The total number of buffer bindings must be <= MTL_MAX_BUFFER_BINDINGS
* We also require an additional 3 core buffers for:
* We also require an additional 2 core buffers for:
* - Argument buffer for bindless resources (e.g. samplers)
* - Transform feedback buffer
* - Default push constant block
* Along with up to 6+1 buffers for vertex data, and index data. */
#define MTL_MAX_BUFFER_BINDINGS 31

View File

@@ -847,7 +847,7 @@ class MTLContext : public Context {
* to every draw call, to ensure that all state is applied and up
* to date. We handle:
*
* - Buffer bindings (Vertex buffers, Uniforms, UBOs, transform feedback)
* - Buffer bindings (Vertex buffers, Uniforms, UBOs)
* - Texture bindings
* - Sampler bindings (+ argument buffer bindings)
* - Dynamic Render pipeline state (on encoder)

View File

@@ -990,32 +990,6 @@ bool MTLContext::ensure_render_pipeline_state(MTLPrimitiveType mtl_prim_type)
this->ensure_texture_bindings(rec, shader_interface, pipeline_state_instance);
}
/* Transform feedback buffer binding. */
VertBuf *tf_vbo = this->pipeline_state.active_shader->get_transform_feedback_active_buffer();
if (tf_vbo != nullptr && pipeline_state_instance->transform_feedback_buffer_index >= 0) {
/* Ensure primitive type is either GPU_LINES, GPU_TRIANGLES or GPU_POINT */
BLI_assert(mtl_prim_type == MTLPrimitiveTypeLine ||
mtl_prim_type == MTLPrimitiveTypeTriangle ||
mtl_prim_type == MTLPrimitiveTypePoint);
/* Fetch active transform feedback buffer from vertbuf */
MTLVertBuf *tf_vbo_mtl = static_cast<MTLVertBuf *>(reinterpret_cast<VertBuf *>(tf_vbo));
/* Ensure TF buffer is ready. */
tf_vbo_mtl->bind();
id<MTLBuffer> tf_buffer_mtl = tf_vbo_mtl->get_metal_buffer();
BLI_assert(tf_buffer_mtl != nil);
if (tf_buffer_mtl != nil) {
[rec setVertexBuffer:tf_buffer_mtl
offset:0
atIndex:pipeline_state_instance->transform_feedback_buffer_index];
MTL_LOG_INFO("Successfully bound VBO: %p for transform feedback (MTL Buffer: %p)",
tf_vbo_mtl,
tf_buffer_mtl);
}
}
/* Matrix Bindings. */
/* This is now called upon shader bind. We may need to re-evaluate this though,
* as was done here to ensure uniform changes between draws were tracked.

View File

@@ -84,8 +84,6 @@ struct MTLRenderPipelineStateInstance {
int base_storage_buffer_index;
/* buffer bind slot used for null attributes (-1 if not needed). */
int null_attribute_buffer_index;
/* buffer bind used for transform feedback output buffer. */
int transform_feedback_buffer_index;
/* Topology class. */
MTLPrimitiveTopologyClass prim_type;
@@ -173,16 +171,6 @@ class MTLShader : public Shader {
/* Context Handle. */
MTLContext *context_ = nullptr;
/** Transform Feedback. */
/* Transform feedback mode. */
eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
/* Transform feedback outputs written to TFB buffer. */
blender::Vector<std::string> tf_output_name_list_;
/* Whether transform feedback is currently active. */
bool transform_feedback_active_ = false;
/* Vertex buffer to write transform feedback data into. */
VertBuf *transform_feedback_vertbuf_ = nullptr;
/** Shader source code. */
MTLShaderBuilder *shd_builder_ = nullptr;
NSString *vertex_function_name_ = @"";
@@ -294,11 +282,6 @@ class MTLShader : public Shader {
std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override;
std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override;
void transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type) override;
bool transform_feedback_enable(VertBuf *buf) override;
void transform_feedback_disable() override;
void bind() override;
void unbind() override;
@@ -335,9 +318,6 @@ class MTLShader : public Shader {
{
return compute_pso_common_state_;
}
/* Transform Feedback. */
VertBuf *get_transform_feedback_active_buffer();
bool has_transform_feedback_varying(std::string str);
private:
/* Generate MSL shader from GLSL source. */

View File

@@ -318,9 +318,7 @@ bool MTLShader::finalize(const shader::ShaderCreateInfo *info)
else {
/* Vertex/Fragment path. */
BLI_assert([vertex_function_name_ length] > 0);
if (transform_feedback_type_ == GPU_SHADER_TFB_NONE) {
BLI_assert([fragment_function_name_ length] > 0);
}
BLI_assert([fragment_function_name_ length] > 0);
BLI_assert([shd_builder_->msl_source_vert_ length] > 0);
}
@@ -361,13 +359,6 @@ bool MTLShader::finalize(const shader::ShaderCreateInfo *info)
shd_builder_->msl_source_compute_ :
shd_builder_->msl_source_frag_);
/* Transform feedback, skip compilation. */
if (src_stage == ShaderStage::FRAGMENT && (transform_feedback_type_ != GPU_SHADER_TFB_NONE))
{
shader_library_frag_ = nil;
break;
}
/* Concatenate common source. */
NSString *str = [NSString stringWithUTF8String:datatoc_mtl_shader_common_msl];
NSString *source_with_header_a = [str stringByAppendingString:source_to_compile];
@@ -473,33 +464,6 @@ bool MTLShader::finalize(const shader::ShaderCreateInfo *info)
return true;
}
void MTLShader::transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type)
{
tf_output_name_list_.clear();
for (int i = 0; i < name_list.size(); i++) {
tf_output_name_list_.append(std::string(name_list[i]));
}
transform_feedback_type_ = geom_type;
}
bool MTLShader::transform_feedback_enable(blender::gpu::VertBuf *buf)
{
BLI_assert(transform_feedback_type_ != GPU_SHADER_TFB_NONE);
BLI_assert(buf);
transform_feedback_active_ = true;
transform_feedback_vertbuf_ = buf;
BLI_assert(static_cast<MTLVertBuf *>(transform_feedback_vertbuf_)->get_usage_type() ==
GPU_USAGE_DEVICE_ONLY);
return true;
}
void MTLShader::transform_feedback_disable()
{
transform_feedback_active_ = false;
transform_feedback_vertbuf_ = nullptr;
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -1138,25 +1102,6 @@ MTLRenderPipelineStateInstance *MTLShader::bake_pipeline_state(
type:MTLDataTypeInt
withName:@"MTL_storage_buffer_base_index"];
/* Transform feedback constant.
* Ensure buffer is placed after existing buffers, including default buffers. */
int MTL_transform_feedback_buffer_index = -1;
if (this->transform_feedback_type_ != GPU_SHADER_TFB_NONE) {
/* If using argument buffers, insert index after argument buffer index. Otherwise, insert
* after uniform buffer bindings. */
MTL_transform_feedback_buffer_index =
MTL_uniform_buffer_base_index +
((mtl_interface->uses_argument_buffer_for_samplers()) ?
(mtl_interface->get_argument_buffer_bind_index(ShaderStage::VERTEX) + 1) :
(mtl_interface->get_max_buffer_index() + 2));
}
if (this->transform_feedback_type_ != GPU_SHADER_TFB_NONE) {
[values setConstantValue:&MTL_transform_feedback_buffer_index
type:MTLDataTypeInt
withName:@"MTL_transform_feedback_buffer_index"];
}
/* Clipping planes. */
int MTL_clip_distances_enabled = (pipeline_descriptor.clipping_plane_enable_mask > 0) ? 1 : 0;
@@ -1226,32 +1171,25 @@ MTLRenderPipelineStateInstance *MTLShader::bake_pipeline_state(
}
}
/* If transform feedback is used, Vertex-only stage */
if (transform_feedback_type_ == GPU_SHADER_TFB_NONE) {
desc.fragmentFunction = [shader_library_frag_ newFunctionWithName:fragment_function_name_
constantValues:values
error:&error];
if (error) {
bool has_error = (
[[error localizedDescription] rangeOfString:@"Compilation succeeded"].location ==
NSNotFound);
desc.fragmentFunction = [shader_library_frag_ newFunctionWithName:fragment_function_name_
constantValues:values
error:&error];
if (error) {
bool has_error = (
[[error localizedDescription] rangeOfString:@"Compilation succeeded"].location ==
NSNotFound);
const char *errors_c_str = [[error localizedDescription] UTF8String];
const StringRefNull source = shd_builder_->glsl_fragment_source_;
const char *errors_c_str = [[error localizedDescription] UTF8String];
const StringRefNull source = shd_builder_->glsl_fragment_source_;
MTLLogParser parser;
print_log({source}, errors_c_str, "FragShader", has_error, &parser);
MTLLogParser parser;
print_log({source}, errors_c_str, "FragShader", has_error, &parser);
/* Only exit out if genuine error and not warning */
if (has_error) {
return nullptr;
}
/* Only exit out if genuine error and not warning */
if (has_error) {
return nullptr;
}
}
else {
desc.fragmentFunction = nil;
desc.rasterizationEnabled = false;
}
/* Setup pixel format state */
for (int color_attachment = 0; color_attachment < GPU_FB_MAX_COLOR_ATTACHMENT;
@@ -1300,12 +1238,6 @@ MTLRenderPipelineStateInstance *MTLShader::bake_pipeline_state(
MTL_MAX_BUFFER_BINDINGS,
"UBO and SSBO bindings exceed the fragment bind table limit.");
/* Transform feedback buffer. */
if (transform_feedback_type_ != GPU_SHADER_TFB_NONE) {
BLI_assert_msg(MTL_transform_feedback_buffer_index < MTL_MAX_BUFFER_BINDINGS,
"Transform feedback buffer binding exceeds the fragment bind table limit.");
}
/* Argument buffer. */
if (mtl_interface->uses_argument_buffer_for_samplers()) {
BLI_assert_msg(mtl_interface->get_argument_buffer_bind_index() < MTL_MAX_BUFFER_BINDINGS,
@@ -1344,7 +1276,6 @@ MTLRenderPipelineStateInstance *MTLShader::bake_pipeline_state(
pso_inst->base_uniform_buffer_index = MTL_uniform_buffer_base_index;
pso_inst->base_storage_buffer_index = MTL_storage_buffer_base_index;
pso_inst->null_attribute_buffer_index = (using_null_buffer) ? null_buffer_index : -1;
pso_inst->transform_feedback_buffer_index = MTL_transform_feedback_buffer_index;
pso_inst->prim_type = prim_type;
pso_inst->reflection_data_available = (reflection_data != nil);
@@ -1612,30 +1543,6 @@ MTLComputePipelineStateInstance *MTLShader::bake_compute_pipeline_state(
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name SSBO-vertex-fetch-mode attribute control.
* \{ */
blender::gpu::VertBuf *MTLShader::get_transform_feedback_active_buffer()
{
if (transform_feedback_type_ == GPU_SHADER_TFB_NONE || !transform_feedback_active_) {
return nullptr;
}
return transform_feedback_vertbuf_;
}
bool MTLShader::has_transform_feedback_varying(std::string str)
{
if (this->transform_feedback_type_ == GPU_SHADER_TFB_NONE) {
return false;
}
return (std::find(tf_output_name_list_.begin(), tf_output_name_list_.end(), str) !=
tf_output_name_list_.end());
}
/** \} */
/* Since this is going to be compiling shaders in a multi-threaded fashion we
* don't want to create an instance per context as we want to restrict the
* number of simultaneous compilation threads to ensure system responsiveness.

View File

@@ -121,7 +121,6 @@
* Uniform buffers <-- MTL_uniform_buffer_base_index+1
* Storage buffers <-- MTL_storage_buffer_base_index
* Samplers/argument buffer table <-- last buffer + 1
* Transform feedback buffer <-- MTL_transform_feedback_buffer_index ~last_buffer+2
*
* Up to a maximum of 31 bindings.
*/
@@ -351,8 +350,6 @@ class MSLGeneratorInterface {
* Final shader uses the intersection between the two sets. */
blender::Vector<MSLVertexOutputAttribute> fragment_input_varyings;
blender::Vector<MSLFragmentOutputAttribute> fragment_outputs;
/* Transform feedback interface. */
blender::Vector<MSLVertexOutputAttribute> vertex_output_varyings_tf;
/* Clip Distances. */
blender::Vector<char> clip_distances;
/* Max bind IDs. */
@@ -378,7 +375,6 @@ class MSLGeneratorInterface {
bool uses_gl_FragStencilRefARB;
bool uses_gpu_layer;
bool uses_gpu_viewport_index;
bool uses_transform_feedback;
bool uses_barycentrics;
/* Compute shader global variables. */
bool uses_gl_GlobalInvocationID;
@@ -426,7 +422,6 @@ class MSLGeneratorInterface {
std::string generate_msl_uniform_structs(ShaderStage shader_stage);
std::string generate_msl_vertex_in_struct();
std::string generate_msl_vertex_out_struct(ShaderStage shader_stage);
std::string generate_msl_vertex_transform_feedback_out_struct(ShaderStage shader_stage);
std::string generate_msl_fragment_struct(bool is_input);
std::string generate_msl_vertex_inputs_string();
std::string generate_msl_fragment_inputs_string();
@@ -440,7 +435,6 @@ class MSLGeneratorInterface {
std::string generate_msl_uniform_block_population(ShaderStage stage);
std::string generate_msl_vertex_attribute_input_population();
std::string generate_msl_vertex_output_population();
std::string generate_msl_vertex_output_tf_population();
std::string generate_msl_fragment_input_population();
std::string generate_msl_fragment_output_population();
std::string generate_msl_uniform_undefs(ShaderStage stage);

View File

@@ -393,15 +393,7 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
/* Verify Source sizes are greater than zero. */
BLI_assert(shd_builder_->glsl_vertex_source_.empty() == false);
if (!msl_iface.uses_transform_feedback) {
BLI_assert(shd_builder_->glsl_fragment_source_.empty() == false);
}
if (transform_feedback_type_ != GPU_SHADER_TFB_NONE) {
/* Ensure #TransformFeedback is configured correctly. */
BLI_assert(tf_output_name_list_.is_empty() == false);
msl_iface.uses_transform_feedback = true;
}
BLI_assert(shd_builder_->glsl_fragment_source_.empty() == false);
/* Concatenate msl_shader_defines to provide functionality mapping
* from GLSL to MSL. Also include additional GPU defines for
@@ -416,9 +408,7 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
}
shd_builder_->glsl_vertex_source_ = msl_defines_string + shd_builder_->glsl_vertex_source_;
if (!msl_iface.uses_transform_feedback) {
shd_builder_->glsl_fragment_source_ = msl_defines_string + shd_builder_->glsl_fragment_source_;
}
shd_builder_->glsl_fragment_source_ = msl_defines_string + shd_builder_->glsl_fragment_source_;
/**** Extract usage of GL globals. ****/
/* NOTE(METAL): Currently still performing fallback string scan, as info->builtins_ does
@@ -454,7 +444,7 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
msl_iface.uses_gpu_viewport_index = bool(info->builtins_ & BuiltinBits::VIEWPORT_INDEX);
/** Identify usage of fragment-shader builtins. */
if (!msl_iface.uses_transform_feedback) {
{
std::smatch gl_special_cases;
msl_iface.uses_gl_PointCoord = bool(info->builtins_ & BuiltinBits::POINT_COORD) ||
shd_builder_->glsl_fragment_source_.find("gl_PointCoord") !=
@@ -645,9 +635,6 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
/* Generate VertexOut and TransformFeedbackOutput structs. */
ss_vertex << msl_iface.generate_msl_vertex_out_struct(ShaderStage::VERTEX);
if (msl_iface.uses_transform_feedback) {
ss_vertex << msl_iface.generate_msl_vertex_transform_feedback_out_struct(ShaderStage::VERTEX);
}
/* Class Closing Bracket to end shader global scope. */
ss_vertex << "};" << std::endl;
@@ -656,7 +643,7 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
ss_vertex << msl_iface.generate_msl_vertex_entry_stub();
/*** Generate FRAGMENT Stage. ***/
if (!msl_iface.uses_transform_feedback) {
{
/* Conditional defines. */
if (msl_iface.use_argument_buffer_for_samplers()) {
@@ -788,14 +775,12 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
vertex_fs << ss_vertex.str();
vertex_fs.close();
if (!msl_iface.uses_transform_feedback) {
std::ofstream fragment_fs;
fragment_fs.open(
(std::string(path_cstr) + "/" + std::string(this->name) + "_GeneratedFragmentShader.msl")
.c_str());
fragment_fs << ss_fragment.str();
fragment_fs.close();
}
std::ofstream fragment_fs;
fragment_fs.open(
(std::string(path_cstr) + "/" + std::string(this->name) + "_GeneratedFragmentShader.msl")
.c_str());
fragment_fs << ss_fragment.str();
fragment_fs.close();
shader_debug_printf(
"Vertex Shader Saved to: %s\n",
@@ -804,9 +789,7 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
/* Set MSL source NSString's. Required by Metal API. */
NSString *msl_final_vert = [NSString stringWithUTF8String:ss_vertex.str().c_str()];
NSString *msl_final_frag = (msl_iface.uses_transform_feedback) ?
(@"") :
([NSString stringWithUTF8String:ss_fragment.str().c_str()]);
NSString *msl_final_frag = [NSString stringWithUTF8String:ss_fragment.str().c_str()];
this->shader_source_from_msl(msl_final_vert, msl_final_frag);
@@ -1364,10 +1347,6 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
max_tex_bind_index = max_ii(max_tex_bind_index, msl_image.slot);
}
}
/* Transform feedback. */
uses_transform_feedback = (create_info_->tf_type_ != GPU_SHADER_TFB_NONE) &&
(create_info_->tf_names_.is_empty() == false);
}
bool MSLGeneratorInterface::use_argument_buffer_for_samplers() const
@@ -1444,12 +1423,7 @@ std::string MSLGeneratorInterface::generate_msl_vertex_entry_stub()
/* Generate function entry point signature w/ resource bindings and inputs. */
out << "vertex ";
if (this->uses_transform_feedback) {
out << "void ";
}
else {
out << get_stage_class_name(ShaderStage::VERTEX) << "::VertexOut ";
}
out << get_stage_class_name(ShaderStage::VERTEX) << "::VertexOut ";
#ifndef NDEBUG
out << "vertex_function_entry_" << parent_shader_.name_get() << "(\n\t";
#else
@@ -1497,14 +1471,7 @@ std::string MSLGeneratorInterface::generate_msl_vertex_entry_stub()
out << "if(is_function_constant_defined(MTL_global_pointsize)){ output.pointsize = "
"(MTL_global_pointsize > 0.0)?MTL_global_pointsize:output.pointsize; }"
<< std::endl;
/* Populate transform feedback buffer. */
if (this->uses_transform_feedback) {
out << this->generate_msl_vertex_output_tf_population();
}
else {
out << "\treturn output;" << std::endl;
}
out << "\treturn output;" << std::endl;
out << "}";
return out.str();
}
@@ -1775,14 +1742,6 @@ std::string MSLGeneratorInterface::generate_msl_vertex_inputs_string()
this->generate_msl_uniforms_input_string(out, ShaderStage::VERTEX, is_first_parameter);
/* Transform feedback buffer binding. */
if (this->uses_transform_feedback) {
out << parameter_delimiter(is_first_parameter) << "\n\tdevice "
<< get_stage_class_name(ShaderStage::VERTEX)
<< "::VertexOut_TF* "
"transform_feedback_results[[buffer(MTL_transform_feedback_buffer_index)]]";
}
/* Generate texture signatures. */
this->generate_msl_textures_input_string(out, ShaderStage::VERTEX, is_first_parameter);
@@ -1994,9 +1953,7 @@ std::string MSLGeneratorInterface::generate_msl_vertex_out_struct(ShaderStage sh
out << "typedef struct {" << std::endl;
/* If we use GL position, our standard output variable will be mapped to '_default_position_'.
* Otherwise, we use the FIRST element in the output array.
* If transform feedback is enabled, we do not need to output position, unless it
* is explicitly specified as a tf output. */
* Otherwise, we use the FIRST element in the output array. */
bool first_attr_is_position = false;
if (this->uses_gl_Position) {
@@ -2008,17 +1965,15 @@ std::string MSLGeneratorInterface::generate_msl_vertex_out_struct(ShaderStage sh
out << ";" << std::endl;
}
else {
if (!this->uses_transform_feedback) {
/* Use first output element for position. */
BLI_assert(this->vertex_output_varyings.is_empty() == false);
BLI_assert(this->vertex_output_varyings[0].type == "vec4");
/* Use first output element for position. */
BLI_assert(this->vertex_output_varyings.is_empty() == false);
BLI_assert(this->vertex_output_varyings[0].type == "vec4");
/* Use invariance if available. See above for detail. */
out << "\tfloat4 " << this->vertex_output_varyings[0].name << " [[position]];";
out << " [[invariant]]";
out << ";" << std::endl;
first_attr_is_position = true;
}
/* Use invariance if available. See above for detail. */
out << "\tfloat4 " << this->vertex_output_varyings[0].name << " [[position]];";
out << " [[invariant]]";
out << ";" << std::endl;
first_attr_is_position = true;
}
/* Generate other vertex output members. */
@@ -2112,85 +2067,6 @@ std::string MSLGeneratorInterface::generate_msl_vertex_out_struct(ShaderStage sh
return out.str();
}
std::string MSLGeneratorInterface::generate_msl_vertex_transform_feedback_out_struct(
ShaderStage shader_stage)
{
BLI_assert(shader_stage == ShaderStage::VERTEX || shader_stage == ShaderStage::FRAGMENT);
UNUSED_VARS_NDEBUG(shader_stage);
std::stringstream out;
vertex_output_varyings_tf.clear();
out << "typedef struct {" << std::endl;
/* If we use GL position, our standard output variable will be mapped to '_default_position_'.
* Otherwise, we use the FIRST element in the output array -- If transform feedback is enabled,
* we do not need to output position */
bool first_attr_is_position = false;
if (this->uses_gl_Position) {
if (parent_shader_.has_transform_feedback_varying("gl_Position")) {
out << "\tfloat4 pos [[position]];" << std::endl;
vertex_output_varyings_tf.append({.type = "vec4",
.name = "gl_Position",
.interpolation_qualifier = "",
.is_array = false,
.array_elems = 1});
}
}
else {
if (!this->uses_transform_feedback) {
/* Use first output element for position */
BLI_assert(this->vertex_output_varyings.is_empty() == false);
BLI_assert(this->vertex_output_varyings[0].type == "vec4");
first_attr_is_position = true;
}
}
/* Generate other vertex outputs. */
bool skip_first_index = first_attr_is_position;
for (const MSLVertexOutputAttribute &v_out : this->vertex_output_varyings) {
/* Skip first index if used for position. */
if (skip_first_index) {
skip_first_index = false;
continue;
}
if (!parent_shader_.has_transform_feedback_varying(v_out.name)) {
continue;
}
vertex_output_varyings_tf.append(v_out);
if (v_out.is_array) {
/* TODO(Metal): Support array of matrix types if required. */
for (int i = 0; i < v_out.array_elems; i++) {
out << "\t" << v_out.type << " " << v_out.name << i
<< v_out.get_mtl_interpolation_qualifier() << ";" << std::endl;
}
}
else {
/* Matrix types need to be expressed as their vector sub-components. */
if (is_matrix_type(v_out.type)) {
BLI_assert(v_out.get_mtl_interpolation_qualifier() == " [[flat]]" &&
"Matrix varying types must have [[flat]] interpolation");
std::string subtype = get_matrix_subtype(v_out.type);
for (int elem = 0; elem < get_matrix_location_count(v_out.type); elem++) {
out << "\t" << subtype << " __matrix_" << v_out.name << elem
<< v_out.get_mtl_interpolation_qualifier() << ";" << std::endl;
}
}
else {
out << "\t" << v_out.type << " " << v_out.name << v_out.get_mtl_interpolation_qualifier()
<< ";" << std::endl;
}
}
}
out << "} VertexOut_TF;" << std::endl << std::endl;
return out.str();
}
std::string MSLGeneratorInterface::generate_msl_fragment_struct(bool is_input)
{
std::stringstream out;
@@ -2499,9 +2375,8 @@ std::string MSLGeneratorInterface::generate_msl_vertex_output_population()
}
else {
/* If we are not using gl_Position, first vertex output is used for position.
* Ensure it is vec4. If transform feedback is enabled, we do not need position. */
if (!this->uses_gl_Position && output_id == 0 && !this->uses_transform_feedback) {
* Ensure it is vec4. */
if (!this->uses_gl_Position && output_id == 0) {
out << "\toutput." << v_out.instance_name << "_" << v_out.name << " = to_vec4("
<< shader_stage_inst_name << "." << v_out.name << ");" << std::endl;
@@ -2510,7 +2385,6 @@ std::string MSLGeneratorInterface::generate_msl_vertex_output_population()
<< v_out.name << ".y;" << std::endl;
}
else {
/* Assign vertex output. */
out << "\toutput." << v_out.instance_name << "_" << v_out.name << " = "
<< shader_stage_inst_name << ".";
@@ -2529,25 +2403,6 @@ std::string MSLGeneratorInterface::generate_msl_vertex_output_population()
return out.str();
}
/* Copy desired output varyings into transform feedback structure */
std::string MSLGeneratorInterface::generate_msl_vertex_output_tf_population()
{
static const char *shader_stage_inst_name = get_shader_stage_instance_name(ShaderStage::VERTEX);
std::stringstream out;
out << "\t/* Copy Vertex TF Outputs into transform feedback buffer */" << std::endl;
/* Populate output vertex variables */
/* TODO(Metal): Currently do not need to support output matrix types etc; but may need to
* verify for other configurations if these occur in any cases. */
for (int v_output = 0; v_output < this->vertex_output_varyings_tf.size(); v_output++) {
out << "transform_feedback_results[gl_VertexID]."
<< this->vertex_output_varyings_tf[v_output].name << " = " << shader_stage_inst_name << "."
<< this->vertex_output_varyings_tf[v_output].name << ";" << std::endl;
}
out << std::endl;
return out.str();
}
/* Copy fragment stage inputs (Vertex Outputs) into local class variables. */
std::string MSLGeneratorInterface::generate_msl_fragment_input_population()
{

View File

@@ -21,9 +21,7 @@ namespace blender::gpu {
class MTLVertBuf : public VertBuf {
friend class gpu::MTLTexture; /* For buffer texture. */
friend class MTLShader; /* For transform feedback. */
friend class MTLBatch;
friend class MTLContext; /* For transform feedback. */
friend class MTLStorageBuf; /* For bind as SSBO resource access and copy sub. */
private:

View File

@@ -590,7 +590,6 @@ void GLBackend::capabilities_init()
glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &ssbo_alignment);
GCaps.storage_buffer_alignment = size_t(ssbo_alignment);
GCaps.transform_feedback_support = true;
GCaps.texture_view_support = epoxy_gl_version() >= 43 ||
epoxy_has_gl_extension("GL_ARB_texture_view");
GCaps.stencil_export_support = epoxy_has_gl_extension("GL_ARB_shader_stencil_export");

View File

@@ -1315,59 +1315,6 @@ void GLShader::unbind()
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform feedback
*
* TODO(fclem): Should be replaced by compute shaders.
* \{ */
void GLShader::transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type)
{
glTransformFeedbackVaryings(
program_get(), name_list.size(), name_list.data(), GL_INTERLEAVED_ATTRIBS);
transform_feedback_type_ = geom_type;
}
bool GLShader::transform_feedback_enable(blender::gpu::VertBuf *buf_)
{
if (transform_feedback_type_ == GPU_SHADER_TFB_NONE) {
return false;
}
GLVertBuf *buf = static_cast<GLVertBuf *>(buf_);
if (buf->vbo_id_ == 0) {
buf->bind();
}
BLI_assert(buf->vbo_id_ != 0);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf->vbo_id_);
switch (transform_feedback_type_) {
case GPU_SHADER_TFB_POINTS:
glBeginTransformFeedback(GL_POINTS);
break;
case GPU_SHADER_TFB_LINES:
glBeginTransformFeedback(GL_LINES);
break;
case GPU_SHADER_TFB_TRIANGLES:
glBeginTransformFeedback(GL_TRIANGLES);
break;
default:
return false;
}
return true;
}
void GLShader::transform_feedback_disable()
{
glEndTransformFeedback();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Uniforms setters
* \{ */

View File

@@ -149,8 +149,6 @@ class GLShader : public Shader {
/** True if any shader failed to compile. */
bool compilation_failed_ = false;
eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
std::string debug_source;
public:
@@ -176,12 +174,6 @@ class GLShader : public Shader {
std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override;
std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override;
/** Should be called before linking. */
void transform_feedback_names_set(Span<const char *> name_list,
eGPUShaderTFBType geom_type) override;
bool transform_feedback_enable(VertBuf *buf) override;
void transform_feedback_disable() override;
void bind() override;
void unbind() override;

View File

@@ -19,7 +19,6 @@ namespace gpu {
class GLVertBuf : public VertBuf {
friend class GLTexture; /* For buffer texture. */
friend class GLShader; /* For transform feedback. */
friend class GLStorageBuf; /* For sub copy. */
private:

View File

@@ -20,11 +20,13 @@ uniform bool srgbTarget = false;
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
{
#ifndef USE_GPU_SHADER_CREATE_INFO
if (srgbTarget) {
vec3 c = max(in_color.rgb, vec3(0.0));
vec3 c1 = c * (1.0 / 12.92);
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
}
#endif
return in_color;
}

View File

@@ -40,10 +40,6 @@ constant int MTL_AttributeConvert13 [[function_constant(15)]];
constant int MTL_AttributeConvert14 [[function_constant(16)]];
constant int MTL_AttributeConvert15 [[function_constant(17)]];
/* Constant to flag binding index of transform feedback buffer.
* Unused if function constant not set. */
constant int MTL_transform_feedback_buffer_index [[function_constant(18)]];
/** Clip distance enablement. */
/* General toggle to control whether any clipping distances are written at all.
* This is an optimization to avoid having the clipping distance shader output

View File

@@ -714,31 +714,6 @@ bool VKShader::finalize_descriptor_set_layouts(VKDevice &vk_device,
return vk_descriptor_set_layout_ != VK_NULL_HANDLE;
}
/* -------------------------------------------------------------------- */
/** \name Transform feedback
*
* Not supported in the vulkan backend.
*
* \{ */
void VKShader::transform_feedback_names_set(Span<const char *> /*name_list*/,
eGPUShaderTFBType /*geom_type*/)
{
BLI_assert_unreachable();
}
bool VKShader::transform_feedback_enable(VertBuf *)
{
return false;
}
void VKShader::transform_feedback_disable()
{
BLI_assert_unreachable();
}
/** \} */
void VKShader::bind()
{
/* Intentionally empty. Binding of the pipeline are done just before drawing/dispatching.

View File

@@ -76,11 +76,6 @@ class VKShader : public Shader {
bool is_ready() const;
void warm_cache(int limit) override;
void transform_feedback_names_set(Span<const char *> name_list,
eGPUShaderTFBType geom_type) override;
bool transform_feedback_enable(VertBuf *) override;
void transform_feedback_disable() override;
void bind() override;
void unbind() override;