Files
test2/source/blender/gpu/intern/gpu_shader_interface.cc
Jason Fielder 335d3a1b75 GPU: Add Shader specialization constant API
Adds API to allow usage of specialization constants in shaders.
Specialization constants are dynamic runtime constants which can
be compiled into a shader pipeline state object (PSO) to improve
runtime performance by reducing shader complexity through
shader compiler constant-folding.

This API allows specialization constant values to be specified
along with a default value if no constant value has been declared.
Each GPU backend is then responsible for caching PSO permutations
against the current specialization configuration.

This patch adds support for specialization constants in the
Metal backend and provides a generalised high-level solution
which can be adopted by other graphics APIs supporting
this feature.

Authored by Apple: Michael Parkin-White
Authored by Blender: Clément Foucault (files in gpu/test folder)

Pull Request: https://projects.blender.org/blender/blender/pulls/115193
2023-12-28 05:34:38 +01:00

126 lines
3.5 KiB
C++

/* SPDX-FileCopyrightText: 2016 by Mike Erwin. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*
* GPU shader interface (C --> GLSL)
*/
#include "MEM_guardedalloc.h"
#include "BLI_span.hh"
#include "BLI_vector.hh"
#include "gpu_shader_interface.hh"
namespace blender::gpu {
/* TODO(fclem): add unique ID for debugging. */
ShaderInterface::ShaderInterface() = default;
ShaderInterface::~ShaderInterface()
{
/* Free memory used by name_buffer. */
MEM_SAFE_FREE(name_buffer_);
MEM_SAFE_FREE(inputs_);
}
static void sort_input_list(MutableSpan<ShaderInput> dst)
{
if (dst.is_empty()) {
return;
}
Vector<ShaderInput> inputs_vec = Vector<ShaderInput>(dst.size());
MutableSpan<ShaderInput> src = inputs_vec.as_mutable_span();
src.copy_from(dst);
/* Simple sorting by going through the array and selecting the biggest element each time. */
for (uint i = 0; i < dst.size(); i++) {
ShaderInput *input_src = src.data();
for (uint j = 1; j < src.size(); j++) {
if (src[j].name_hash > input_src->name_hash) {
input_src = &src[j];
}
}
dst[i] = *input_src;
input_src->name_hash = 0;
}
}
void ShaderInterface::sort_inputs()
{
/* Sorts all inputs inside their respective array.
* This is to allow fast hash collision detection.
* See `ShaderInterface::input_lookup` for more details. */
uint offset = 0;
sort_input_list(MutableSpan<ShaderInput>(inputs_ + offset, attr_len_));
offset += attr_len_;
sort_input_list(MutableSpan<ShaderInput>(inputs_ + offset, ubo_len_));
offset += ubo_len_;
sort_input_list(MutableSpan<ShaderInput>(inputs_ + offset, uniform_len_));
offset += uniform_len_;
sort_input_list(MutableSpan<ShaderInput>(inputs_ + offset, ssbo_len_));
offset += ssbo_len_;
sort_input_list(MutableSpan<ShaderInput>(inputs_ + offset, constant_len_));
offset += constant_len_;
}
void ShaderInterface::debug_print() const
{
Span<ShaderInput> attrs = Span<ShaderInput>(inputs_, attr_len_);
Span<ShaderInput> ubos = Span<ShaderInput>(inputs_ + attr_len_, ubo_len_);
Span<ShaderInput> uniforms = Span<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_);
Span<ShaderInput> ssbos = Span<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_,
ssbo_len_);
char *name_buf = name_buffer_;
const char format[] = " | %.8x : %4d : %s\n";
if (attrs.size() > 0) {
printf("\n Attributes :\n");
}
for (const ShaderInput &attr : attrs) {
printf(format, attr.name_hash, attr.location, name_buf + attr.name_offset);
}
if (uniforms.size() > 0) {
printf("\n Uniforms :\n");
}
for (const ShaderInput &uni : uniforms) {
/* Bypass samplers. */
if (uni.binding == -1) {
printf(format, uni.name_hash, uni.location, name_buf + uni.name_offset);
}
}
if (ubos.size() > 0) {
printf("\n Uniform Buffer Objects :\n");
}
for (const ShaderInput &ubo : ubos) {
printf(format, ubo.name_hash, ubo.binding, name_buf + ubo.name_offset);
}
if (enabled_tex_mask_ > 0) {
printf("\n Samplers :\n");
}
for (const ShaderInput &samp : uniforms) {
/* Bypass uniforms. */
if (samp.binding != -1) {
printf(format, samp.name_hash, samp.binding, name_buf + samp.name_offset);
}
}
if (ssbos.size() > 0) {
printf("\n Shader Storage Objects :\n");
}
for (const ShaderInput &ssbo : ssbos) {
printf(format, ssbo.name_hash, ssbo.binding, name_buf + ssbo.name_offset);
}
printf("\n");
}
} // namespace blender::gpu