1
1

Compare commits

...

16 Commits

22 changed files with 843 additions and 13 deletions

View File

@@ -401,6 +401,7 @@ GPUShader *DRW_shader_create_with_transform_feedback(const char *vert,
prim_type,
varying_names,
varying_count,
GPU_SHADER_BLOCK_CUSTOM,
__func__);
}

View File

@@ -81,6 +81,7 @@ set(SRC
intern/gpu_select_pick.c
intern/gpu_select_sample_query.cc
intern/gpu_shader.cc
intern/gpu_shader_block.cc
intern/gpu_shader_builtin.c
intern/gpu_shader_log.cc
intern/gpu_shader_interface.cc
@@ -400,6 +401,7 @@ if(WITH_GTESTS)
tests/gpu_index_buffer_test.cc
tests/gpu_shader_builtin_test.cc
tests/gpu_shader_test.cc
tests/gpu_shader_block_test.cc
tests/gpu_testing.hh
)

View File

@@ -23,6 +23,8 @@
#pragma once
#include "GPU_shader_block_types.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -64,10 +66,12 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
const eGPUShaderTFBType tf_type,
const char **tf_names,
const int tf_count,
const GPUShaderBlockType uniform_struct_type,
const char *shname);
struct GPU_ShaderCreateFromArray_Params {
const char **vert, **geom, **frag, **defs;
const GPUShaderBlockType shader_block;
};
struct GPUShader *GPU_shader_create_from_arrays_impl(
const struct GPU_ShaderCreateFromArray_Params *params, const char *func, int line);
@@ -122,6 +126,7 @@ typedef enum {
GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */
GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */
GPU_UNIFORM_BLOCK_INFO, /* infoBlock */
GPU_UNIFORM_BLOCK_SHADER, /* shaderBlock */
GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */
} GPUUniformBlockBuiltin;

View File

@@ -0,0 +1,51 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2021 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup gpu
*/
#pragma once
#include "BLI_assert.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum GPUShaderBlockType {
GPU_SHADER_BLOCK_CUSTOM = 0,
GPU_SHADER_BLOCK_3D_COLOR,
GPU_NUM_SHADER_BLOCK_TYPES, /* Special value, denotes number of structs. */
} GPUShaderBlockType;
typedef struct GPUShaderBlock3dColor {
float ModelMatrix[4][4];
float ModelViewProjectionMatrix[4][4];
float color[4];
float WorldClipPlanes[6][4];
int SrgbTransform;
int _pad[3];
} GPUShaderBlock3dColor;
BLI_STATIC_ASSERT_ALIGN(GPUShaderBlock3dColor, 16)
#ifdef __cplusplus
}
#endif

View File

@@ -23,6 +23,8 @@
#include "MEM_guardedalloc.h"
#include "BKE_global.h"
#include "BLI_string_utils.h"
#include "GPU_capabilities.h"
@@ -32,6 +34,11 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
#include "gpu_shader_private.hh"
#include "gpu_uniform_buffer_private.hh"
#include "CLG_log.h"
static CLG_LogRef LOG = {"gpu.shader"};
extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[];
@@ -52,6 +59,31 @@ Shader::Shader(const char *sh_name)
Shader::~Shader()
{
delete interface;
delete m_shader_struct;
}
const bool Shader::has_shader_block() const
{
return m_shader_struct;
}
const bool Shader::shader_block_dirty_get() const
{
BLI_assert(m_shader_struct);
return m_shader_struct->flags().is_dirty;
}
void Shader::shader_block_update() const
{
BLI_assert(m_shader_struct);
m_shader_struct->update();
}
void Shader::shader_block_bind() const
{
BLI_assert(m_shader_struct);
const int binding = interface->ubo_builtin(GPU_UNIFORM_BLOCK_SHADER);
m_shader_struct->bind(binding);
}
static void standard_defines(Vector<const char *> &sources)
@@ -94,6 +126,7 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
const eGPUShaderTFBType tf_type,
const char **tf_names,
const int tf_count,
const GPUShaderBlockType shader_block,
const char *shname)
{
/* At least a vertex shader and a fragment shader are required, or only a compute shader. */
@@ -102,6 +135,9 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
(computecode != nullptr)));
Shader *shader = GPUBackend::get()->shader_alloc(shname);
if (shader_block != GPU_SHADER_BLOCK_CUSTOM) {
shader->set_shader_struct(shader_block);
}
if (vertcode) {
Vector<const char *> sources;
@@ -114,6 +150,10 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
if (defines) {
sources.append(defines);
}
if (shader->m_shader_struct) {
sources.append("#define GPU_SHADER_BLOCK\n");
sources.append(shader->m_shader_struct->type_info().defines());
}
sources.append(vertcode);
shader->vertex_shader_from_glsl(sources);
@@ -130,6 +170,10 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
if (defines) {
sources.append(defines);
}
if (shader->m_shader_struct) {
sources.append("#define GPU_SHADER_BLOCK\n");
sources.append(shader->m_shader_struct->type_info().defines());
}
if (libcode) {
sources.append(libcode);
}
@@ -145,6 +189,10 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
if (defines) {
sources.append(defines);
}
if (shader->m_shader_struct) {
sources.append("#define GPU_SHADER_BLOCK\n");
sources.append(shader->m_shader_struct->type_info().defines());
}
sources.append(geomcode);
shader->geometry_shader_from_glsl(sources);
@@ -160,6 +208,10 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
if (libcode) {
sources.append(libcode);
}
if (shader->m_shader_struct) {
sources.append("#define GPU_SHADER_BLOCK\n");
sources.append(shader->m_shader_struct->type_info().defines());
}
sources.append(computecode);
shader->compute_shader_from_glsl(sources);
@@ -175,6 +227,21 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
return nullptr;
};
if (G.debug & G_DEBUG_GPU) {
std::optional<GPUShaderBlockType> best_struct_type = find_smallest_shader_block(
*shader->interface);
if (best_struct_type) {
if (/*uniform_struct_type != GPU_SHADER_BLOCK_CUSTOM &&*/
shader_block != *best_struct_type) {
CLOG_WARN(&LOG,
"Found better matching uniform struct for '%s'; current %d, suggested %d",
shname,
static_cast<int>(shader_block),
static_cast<int>(*best_struct_type));
}
}
return wrap(shader);
}
@@ -205,6 +272,7 @@ GPUShader *GPU_shader_create(const char *vertcode,
GPU_SHADER_TFB_NONE,
nullptr,
0,
GPU_SHADER_BLOCK_CUSTOM,
shname);
}
@@ -222,6 +290,7 @@ GPUShader *GPU_shader_create_compute(const char *computecode,
GPU_SHADER_TFB_NONE,
nullptr,
0,
GPU_SHADER_BLOCK_CUSTOM,
shname);
}
@@ -249,6 +318,7 @@ GPUShader *GPU_shader_create_from_python(const char *vertcode,
GPU_SHADER_TFB_NONE,
nullptr,
0,
GPU_SHADER_BLOCK_CUSTOM,
"pyGPUShader");
MEM_SAFE_FREE(libcodecat);
@@ -316,8 +386,17 @@ struct GPUShader *GPU_shader_create_from_arrays_impl(
char name[64];
BLI_snprintf(name, sizeof(name), "%s_%d", func, line);
GPUShader *sh = GPU_shader_create(
str_dst[0].str, str_dst[1].str, str_dst[2].str, nullptr, str_dst[3].str, name);
GPUShader *sh = GPU_shader_create_ex(str_dst[0].str,
str_dst[1].str,
str_dst[2].str,
nullptr,
nullptr,
str_dst[3].str,
GPU_SHADER_TFB_NONE,
nullptr,
0,
params->shader_block,
name);
for (auto &i : str_dst) {
if (i.is_alloc) {
@@ -353,6 +432,13 @@ void GPU_shader_bind(GPUShader *gpu_shader)
GPU_matrix_bind(gpu_shader);
}
}
if (shader->has_shader_block()) {
if (shader->shader_block_dirty_get()) {
shader->shader_block_update();
}
shader->shader_block_bind();
}
}
void GPU_shader_unbind(void)

View File

@@ -0,0 +1,313 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2021 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup gpu
*/
#include "gpu_uniform_buffer_private.hh"
#include "MEM_guardedalloc.h"
#include "GPU_shader.h"
#include "gpu_shader_block.hh"
#include "gpu_shader_interface.hh"
#include "BLI_string_ref.hh"
namespace blender::gpu {
/* -------------------------------------------------------------------- */
/** \name Attribute bindings
* \{ */
const int BUILTIN_BINDING_LOCATION_OFFSET = 1000;
static constexpr int to_binding_location(const GPUUniformBuiltin builtin_uniform)
{
return BUILTIN_BINDING_LOCATION_OFFSET + builtin_uniform;
}
static GPUUniformBuiltin to_builtin_uniform(int location)
{
return static_cast<GPUUniformBuiltin>(location - BUILTIN_BINDING_LOCATION_OFFSET);
}
static bool is_valid_location(int location)
{
int builtin_uniform = location - BUILTIN_BINDING_LOCATION_OFFSET;
if (builtin_uniform < 0 || builtin_uniform >= GPU_NUM_UNIFORMS) {
return false;
}
return true;
}
static constexpr ShaderBlockType::AttributeBinding determine_location_3d_color(
const GPUUniformBuiltin builtin_uniform)
{
ShaderBlockType::AttributeBinding result = {-1, 0};
switch (builtin_uniform) {
case GPU_UNIFORM_MODEL:
result.location = to_binding_location(builtin_uniform);
result.offset = offsetof(GPUShaderBlock3dColor, ModelMatrix);
break;
case GPU_UNIFORM_MVP:
result.location = to_binding_location(builtin_uniform);
result.offset = offsetof(GPUShaderBlock3dColor, ModelViewProjectionMatrix);
break;
case GPU_UNIFORM_COLOR:
result.location = to_binding_location(builtin_uniform);
result.offset = offsetof(GPUShaderBlock3dColor, color);
break;
case GPU_UNIFORM_CLIPPLANES:
result.location = to_binding_location(builtin_uniform);
result.offset = offsetof(GPUShaderBlock3dColor, WorldClipPlanes);
break;
case GPU_UNIFORM_SRGB_TRANSFORM:
result.location = to_binding_location(builtin_uniform);
result.offset = offsetof(GPUShaderBlock3dColor, SrgbTransform);
break;
default:
break;
};
return result;
}
static constexpr ShaderBlockType::AttributeBinding determine_binding(
const GPUShaderBlockType block_type, const GPUUniformBuiltin builtin_uniform)
{
switch (block_type) {
case GPU_SHADER_BLOCK_CUSTOM:
case GPU_NUM_SHADER_BLOCK_TYPES:
return {};
case GPU_SHADER_BLOCK_3D_COLOR:
return determine_location_3d_color(builtin_uniform);
};
return {};
}
static constexpr std::array<const ShaderBlockType::AttributeBinding, GPU_NUM_UNIFORMS>
builtin_uniforms_for_struct_type(const GPUShaderBlockType block_type)
{
return {
determine_binding(block_type, GPU_UNIFORM_MODEL),
determine_binding(block_type, GPU_UNIFORM_VIEW),
determine_binding(block_type, GPU_UNIFORM_MODELVIEW),
determine_binding(block_type, GPU_UNIFORM_PROJECTION),
determine_binding(block_type, GPU_UNIFORM_VIEWPROJECTION),
determine_binding(block_type, GPU_UNIFORM_MVP),
determine_binding(block_type, GPU_UNIFORM_MODEL_INV),
determine_binding(block_type, GPU_UNIFORM_VIEW_INV),
determine_binding(block_type, GPU_UNIFORM_MODELVIEW_INV),
determine_binding(block_type, GPU_UNIFORM_PROJECTION_INV),
determine_binding(block_type, GPU_UNIFORM_VIEWPROJECTION_INV),
determine_binding(block_type, GPU_UNIFORM_NORMAL),
determine_binding(block_type, GPU_UNIFORM_ORCO),
determine_binding(block_type, GPU_UNIFORM_CLIPPLANES),
determine_binding(block_type, GPU_UNIFORM_COLOR),
determine_binding(block_type, GPU_UNIFORM_BASE_INSTANCE),
determine_binding(block_type, GPU_UNIFORM_RESOURCE_CHUNK),
determine_binding(block_type, GPU_UNIFORM_RESOURCE_ID),
determine_binding(block_type, GPU_UNIFORM_SRGB_TRANSFORM),
};
}
static constexpr std::array<
const std::array<const ShaderBlockType::AttributeBinding, GPU_NUM_UNIFORMS>,
GPU_NUM_SHADER_BLOCK_TYPES>
ATTRIBUTE_BINDINGS = {
builtin_uniforms_for_struct_type(GPU_SHADER_BLOCK_CUSTOM),
builtin_uniforms_for_struct_type(GPU_SHADER_BLOCK_3D_COLOR),
};
static constexpr size_t data_size_for(const GPUShaderBlockType block_type)
{
switch (block_type) {
case GPU_SHADER_BLOCK_CUSTOM:
case GPU_NUM_SHADER_BLOCK_TYPES:
return 0;
case GPU_SHADER_BLOCK_3D_COLOR:
return sizeof(GPUShaderBlock3dColor);
};
return 0;
}
static constexpr StringRef DEFINES_3D_COLOR = R"(
layout(std140) uniform shaderBlock {
mat4 ModelMatrix;
mat4 ModelViewProjectionMatrix;
vec4 color;
vec4 WorldClipPlanes[6];
bool srgbTarget;
};
)";
static constexpr const char *defines_for(const GPUShaderBlockType type)
{
switch (type) {
case GPU_SHADER_BLOCK_CUSTOM:
case GPU_NUM_SHADER_BLOCK_TYPES:
return nullptr;
case GPU_SHADER_BLOCK_3D_COLOR:
return DEFINES_3D_COLOR.data();
};
return nullptr;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Struct type
* \{ */
constexpr ShaderBlockType::ShaderBlockType(const GPUShaderBlockType type)
: type(type),
m_attribute_bindings(ATTRIBUTE_BINDINGS[type]),
m_data_size(data_size_for(type)),
m_defines(defines_for(type))
{
}
bool ShaderBlockType::AttributeBinding::has_binding() const
{
return location != -1;
}
bool ShaderBlockType::has_all_builtin_uniforms(const ShaderInterface &interface) const
{
for (int i = 0; i < GPU_NUM_UNIFORMS; i++) {
const GPUUniformBuiltin builtin_uniform = static_cast<const GPUUniformBuiltin>(i);
const AttributeBinding &binding = attribute_binding(builtin_uniform);
const bool builtin_is_used = interface.builtins_[i] != -1;
const bool has_attribute = binding.has_binding();
if (builtin_is_used && !has_attribute) {
return false;
}
}
return true;
}
static constexpr std::array<ShaderBlockType, GPU_NUM_SHADER_BLOCK_TYPES> STRUCT_TYPE_INFOS = {
ShaderBlockType(GPU_SHADER_BLOCK_CUSTOM),
ShaderBlockType(GPU_SHADER_BLOCK_3D_COLOR),
};
const ShaderBlockType &ShaderBlockType::get(const GPUShaderBlockType type)
{
return STRUCT_TYPE_INFOS[type];
}
std::optional<const GPUShaderBlockType> find_smallest_shader_block(
const ShaderInterface &interface)
{
if (!interface.has_builtin_uniforms()) {
return std::nullopt;
}
if (ShaderBlockType::get(GPU_SHADER_BLOCK_3D_COLOR).has_all_builtin_uniforms(interface)) {
return std::make_optional(GPU_SHADER_BLOCK_3D_COLOR);
}
return std::nullopt;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Struct type
* \{ */
ShaderBlockBuffer::ShaderBlockBuffer(const GPUShaderBlockType type)
: m_type_info(ShaderBlockType::get(type))
{
m_data = MEM_mallocN(m_type_info.data_size(), __func__);
m_ubo = GPUBackend::get()->uniformbuf_alloc(m_type_info.data_size(), __func__);
}
ShaderBlockBuffer::~ShaderBlockBuffer()
{
delete m_ubo;
m_ubo = nullptr;
MEM_freeN(m_data);
m_data = nullptr;
}
bool ShaderBlockBuffer::uniform_int(int location, int comp_len, int array_size, const int *data)
{
if (!is_valid_location(location)) {
return false;
}
const GPUUniformBuiltin builtin_uniform = to_builtin_uniform(location);
const ShaderBlockType::AttributeBinding &attribute = m_type_info.attribute_binding(
builtin_uniform);
if (!attribute.has_binding()) {
return false;
}
const size_t attribute_len = comp_len * array_size * sizeof(int);
memcpy(((uint8_t *)m_data) + attribute.offset, data, attribute_len);
m_flags.is_dirty = true;
return true;
}
bool ShaderBlockBuffer::uniform_float(int location,
int comp_len,
int array_size,
const float *data)
{
if (!is_valid_location(location)) {
return false;
}
const GPUUniformBuiltin builtin_uniform = to_builtin_uniform(location);
const ShaderBlockType::AttributeBinding &attribute = m_type_info.attribute_binding(
builtin_uniform);
if (!attribute.has_binding()) {
return false;
}
const size_t attribute_len = comp_len * array_size * sizeof(float);
memcpy(((uint8_t *)m_data) + attribute.offset, data, attribute_len);
m_flags.is_dirty = true;
return true;
}
void ShaderBlockBuffer::update()
{
if (m_flags.is_dirty) {
m_ubo->update(m_data);
m_flags.is_dirty = false;
}
}
void ShaderBlockBuffer::bind(int binding)
{
m_ubo->bind(binding);
}
/** \} */
} // namespace blender::gpu

View File

@@ -0,0 +1,116 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2021, Blender Foundation.
*/
/** \file
* \ingroup gpu
*/
#pragma once
#include "BLI_sys_types.h"
#include <optional>
#include "GPU_shader_block_types.h"
#include "gpu_backend.hh"
#include "gpu_shader_interface.hh"
#include "gpu_uniform_buffer_private.hh"
#include <array>
namespace blender::gpu {
class ShaderBlockType {
public:
constexpr ShaderBlockType(const GPUShaderBlockType type);
static const ShaderBlockType &get(const GPUShaderBlockType type);
bool has_all_builtin_uniforms(const ShaderInterface &interface) const;
GPUShaderBlockType type;
struct AttributeBinding {
int location = -1;
size_t offset = 0;
bool has_binding() const;
};
const AttributeBinding &attribute_binding(const GPUUniformBuiltin builtin_uniform) const
{
return m_attribute_bindings[builtin_uniform];
}
size_t data_size() const
{
return m_data_size;
}
const char *defines() const
{
return m_defines;
}
private:
const std::array<const AttributeBinding, GPU_NUM_UNIFORMS> &m_attribute_bindings;
const size_t m_data_size;
const char *m_defines;
};
class ShaderBlockBuffer {
public:
struct Flags {
bool is_dirty : 1;
};
ShaderBlockBuffer(const GPUShaderBlockType type);
ShaderBlockBuffer(const ShaderBlockBuffer &other) = default;
ShaderBlockBuffer(ShaderBlockBuffer &&other) = default;
~ShaderBlockBuffer();
const Flags &flags() const
{
return m_flags;
}
void *data() const
{
return m_data;
};
const ShaderBlockType &type_info() const
{
return m_type_info;
}
bool uniform_int(int location, int comp_len, int array_size, const int *data);
bool uniform_float(int location, int comp_len, int array_size, const float *data);
void update();
void bind(int binding);
private:
Flags m_flags;
const ShaderBlockType &m_type_info;
void *m_data;
UniformBuf *m_ubo;
};
std::optional<const GPUShaderBlockType> find_smallest_shader_block(
const ShaderInterface &interface);
} // namespace blender::gpu

View File

@@ -157,6 +157,7 @@ typedef struct {
const char *frag;
/** Optional. */
const char *defs;
const GPUShaderBlockType shader_block;
} GPUShaderStages;
static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
@@ -165,6 +166,7 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.name = "GPU_SHADER_TEXT",
.vert = datatoc_gpu_shader_text_vert_glsl,
.frag = datatoc_gpu_shader_text_frag_glsl,
.shader_block = GPU_SHADER_BLOCK_3D_COLOR,
},
[GPU_SHADER_KEYFRAME_DIAMOND] =
{
@@ -532,6 +534,7 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
.geom = (const char *[]){stages->geom, NULL},
.frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
.defs = (const char *[]){stages->defs, NULL},
.shader_block = stages->shader_block,
});
}
else if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {

View File

@@ -129,4 +129,14 @@ void ShaderInterface::debug_print()
printf("\n");
}
bool ShaderInterface::has_builtin_uniforms() const
{
for (int i = 0; i < GPU_NUM_UNIFORMS; i++) {
if (builtins_[i] != -1) {
return true;
}
}
return false;
}
} // namespace blender::gpu

View File

@@ -35,6 +35,8 @@
#include "GPU_shader.h"
#include <optional>
namespace blender::gpu {
typedef struct ShaderInput {
@@ -75,6 +77,7 @@ class ShaderInterface {
virtual ~ShaderInterface();
void debug_print(void);
bool has_builtin_uniforms() const;
inline const ShaderInput *attr_get(const char *name) const
{
@@ -202,6 +205,8 @@ inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBu
return "modelBlock";
case GPU_UNIFORM_BLOCK_INFO:
return "infoBlock";
case GPU_UNIFORM_BLOCK_SHADER:
return "shaderBlock";
default:
return NULL;
}

View File

@@ -24,9 +24,14 @@
#include "BLI_string_ref.hh"
#include "GPU_shader.h"
#include "GPU_shader_block_types.h"
#include "gpu_shader_block.hh"
#include "gpu_shader_interface.hh"
#include "gpu_uniform_buffer_private.hh"
#include "gpu_vertex_buffer_private.hh"
#include <optional>
namespace blender {
namespace gpu {
@@ -45,6 +50,8 @@ class Shader {
/** For debugging purpose. */
char name[64];
std::optional<ShaderBlockBuffer> shader_struct;
public:
Shader(const char *name);
virtual ~Shader();
@@ -76,6 +83,17 @@ class Shader {
return name;
};
ShaderBlockBuffer *m_shader_struct = nullptr;
void set_shader_struct(GPUShaderBlockType struct_type)
{
m_shader_struct = new ShaderBlockBuffer(struct_type);
}
const bool has_shader_block() const;
const bool shader_block_dirty_get() const;
void shader_block_update() const;
void shader_block_bind() const;
protected:
void print_log(Span<const char *> sources,
char *log,

View File

@@ -24,11 +24,20 @@
#include "BLI_sys_types.h"
#include <optional>
#include "GPU_shader.h"
#include "GPU_shader_block_types.h"
#include <array>
struct GPUUniformBuf;
namespace blender {
namespace gpu {
class ShaderInterface;
#ifdef DEBUG
# define DEBUG_NAME_LEN 64
#else

View File

@@ -225,8 +225,9 @@ bool GLShader::finalize()
this->print_log(sources, log, "Linking", true, &parser);
return false;
}
interface = new GLShaderInterface(shader_program_);
const ShaderBlockType *type_info = m_shader_struct != nullptr ? &m_shader_struct->type_info() :
nullptr;
interface = new GLShaderInterface(type_info, shader_program_);
return true;
}
@@ -308,6 +309,12 @@ void GLShader::transform_feedback_disable()
void GLShader::uniform_float(int location, int comp_len, int array_size, const float *data)
{
if (m_shader_struct) {
if (m_shader_struct->uniform_float(location, comp_len, array_size, data)) {
return;
}
}
switch (comp_len) {
case 1:
glUniform1fv(location, array_size, data);
@@ -335,6 +342,12 @@ void GLShader::uniform_float(int location, int comp_len, int array_size, const f
void GLShader::uniform_int(int location, int comp_len, int array_size, const int *data)
{
if (m_shader_struct) {
if (m_shader_struct->uniform_int(location, comp_len, array_size, data)) {
return;
}
}
switch (comp_len) {
case 1:
glUniform1iv(location, array_size, data);

View File

@@ -145,7 +145,7 @@ static inline int ssbo_binding(int32_t program, uint32_t ssbo_index)
/** \name Creation / Destruction
* \{ */
GLShaderInterface::GLShaderInterface(GLuint program)
GLShaderInterface::GLShaderInterface(const ShaderBlockType *type_info, GLuint program)
{
/* Necessary to make #glUniform works. */
glUseProgram(program);
@@ -187,6 +187,20 @@ GLShaderInterface::GLShaderInterface(GLuint program)
max_ssbo_name_len = 256;
}
/* Perform uniform builtin structs after work around to make sure the work around is passed. */
if (type_info) {
for (int i = 0; i < GPU_NUM_UNIFORMS; i++) {
const GPUUniformBuiltin builtin_uniform = static_cast<const GPUUniformBuiltin>(i);
const ShaderBlockType::AttributeBinding &binding = type_info->attribute_binding(
builtin_uniform);
if (binding.has_binding()) {
uniform_len++;
max_uniform_name_len = max_ii(max_uniform_name_len,
strlen(builtin_uniform_name(builtin_uniform)));
}
}
}
/* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before
* allocating the uniform array. */
GLint max_ubo_uni_len = 0;
@@ -281,6 +295,24 @@ GLShaderInterface::GLShaderInterface(GLuint program)
enabled_ima_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
}
}
if (type_info) {
for (int i = 0; i < GPU_NUM_UNIFORMS; i++) {
const GPUUniformBuiltin builtin_uniform = static_cast<const GPUUniformBuiltin>(i);
const ShaderBlockType::AttributeBinding &binding = type_info->attribute_binding(
builtin_uniform);
if (binding.has_binding()) {
ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_++];
input->location = binding.location;
input->binding = -1;
char *name = name_buffer_ + name_buffer_offset;
const char *uniform_name = builtin_uniform_name(builtin_uniform);
size_t name_len = strlen(uniform_name);
strcpy(name, uniform_name);
name_buffer_offset += this->set_input_name(input, name, name_len);
}
}
}
/* SSBOs */
for (int i = 0; i < ssbo_len; i++) {
@@ -301,7 +333,8 @@ GLShaderInterface::GLShaderInterface(GLuint program)
/* Builtin Uniforms */
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
builtins_[u] = glGetUniformLocation(program, builtin_uniform_name(u));
const ShaderInput *block = this->uniform_get(builtin_uniform_name(u));
builtins_[u] = (block != nullptr) ? block->location : -1;
}
/* Builtin Uniforms Blocks */

View File

@@ -34,6 +34,7 @@
#include "glew-mx.h"
#include "gpu_shader_block.hh"
#include "gpu_shader_interface.hh"
namespace blender::gpu {
@@ -49,7 +50,7 @@ class GLShaderInterface : public ShaderInterface {
Vector<GLVaoCache *> refs_;
public:
GLShaderInterface(GLuint program);
GLShaderInterface(const ShaderBlockType *type_info, GLuint program);
~GLShaderInterface();
void ref_add(GLVaoCache *ref);

View File

@@ -2,7 +2,9 @@
/* Undefine the macro that avoids compilation errors. */
#undef blender_srgb_to_framebuffer_space
#ifndef GPU_SHADER_BLOCK
uniform bool srgbTarget = false;
#endif
vec4 blender_srgb_to_framebuffer_space(vec4 color)
{

View File

@@ -1,6 +1,4 @@
uniform mat4 ModelViewProjectionMatrix;
in vec4 pos; /* rect */
in vec4 col;
in int offset;

View File

@@ -0,0 +1,164 @@
#include "gpu_testing.hh"
#include "GPU_capabilities.h"
#include "GPU_compute.h"
#include "GPU_shader.h"
#include "GPU_shader_block_types.h"
#include "gpu_shader_block.hh"
#include "BLI_math.h"
namespace blender::gpu::tests {
TEST(GPUUniformStruct, struct1)
{
ShaderBlockBuffer uniform_struct(GPU_SHADER_BLOCK_3D_COLOR);
const ShaderBlockType &type_info = uniform_struct.type_info();
const GPUShaderBlock3dColor *struct_data = static_cast<const GPUShaderBlock3dColor *>(
uniform_struct.data());
EXPECT_EQ(type_info.data_size(), sizeof(*struct_data));
/* ModelMatrix attribute. */
{
const ShaderBlockType::AttributeBinding &binding = type_info.attribute_binding(
GPU_UNIFORM_MODEL);
float m4[4][4];
unit_m4(m4);
const bool result = uniform_struct.uniform_float(binding.location, 4, 4, (const float *)m4);
EXPECT_TRUE(result);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
EXPECT_EQ(struct_data->ModelMatrix[i][j], m4[i][j]);
}
}
}
/* ModelViewProjectionMatrix attribute. */
{
const ShaderBlockType::AttributeBinding &binding = type_info.attribute_binding(
GPU_UNIFORM_MVP);
float m4[4][4];
unit_m4(m4);
const bool result = uniform_struct.uniform_float(binding.location, 4, 4, (const float *)m4);
EXPECT_TRUE(result);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
EXPECT_EQ(struct_data->ModelViewProjectionMatrix[i][j], m4[i][j]);
}
}
}
/* Color attribute. */
{
const ShaderBlockType::AttributeBinding &binding = type_info.attribute_binding(
GPU_UNIFORM_COLOR);
float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
const bool result = uniform_struct.uniform_float(binding.location, 4, 1, color);
EXPECT_TRUE(result);
for (int i = 0; i < 4; i++) {
EXPECT_EQ(struct_data->color[i], color[i]);
}
}
/* WorldClipPlanes attribute. */
{
const ShaderBlockType::AttributeBinding &binding = type_info.attribute_binding(
GPU_UNIFORM_CLIPPLANES);
float clip_planes[6][4] = {
{01.0f, 02.0f, 03.0f, 04.0f},
{11.0f, 12.0f, 13.0f, 14.0f},
{21.0f, 22.0f, 23.0f, 24.0f},
{31.0f, 32.0f, 33.0f, 34.0f},
{41.0f, 42.0f, 43.0f, 44.0f},
{51.0f, 52.0f, 53.0f, 54.0f},
};
const bool result = uniform_struct.uniform_float(
binding.location, 4, 6, (const float *)clip_planes);
EXPECT_TRUE(result);
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 4; j++) {
EXPECT_EQ(struct_data->WorldClipPlanes[i][j], clip_planes[i][j]);
}
}
}
/* SrgbTransform attribute. */
{
const ShaderBlockType::AttributeBinding &binding = type_info.attribute_binding(
GPU_UNIFORM_SRGB_TRANSFORM);
int srgb_transform = true;
const bool result = uniform_struct.uniform_int(binding.location, 1, 1, &srgb_transform);
EXPECT_TRUE(result);
EXPECT_EQ(struct_data->SrgbTransform, srgb_transform);
}
}
static void test_shader_block_struct()
{
if (!GPU_compute_shader_support()) {
/* We can't test as a the platform does not support compute shaders. */
std::cout << "Skipping compute shader test: platform not supported";
return;
}
/* Build compute shader. */
const char *compute_glsl = R"(
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img_output;
void main() {
}
)";
GPUShader *shader = GPU_shader_create_ex(nullptr,
nullptr,
nullptr,
compute_glsl,
nullptr,
nullptr,
GPU_SHADER_TFB_NONE,
nullptr,
0,
GPU_SHADER_BLOCK_3D_COLOR,
__func__);
EXPECT_NE(shader, nullptr);
int location;
location = GPU_shader_get_uniform(shader, "ModelMatrix");
EXPECT_NE(location, -1);
location = GPU_shader_get_uniform(shader, "ModelViewProjectionMatrix");
EXPECT_NE(location, -1);
location = GPU_shader_get_uniform(shader, "color");
EXPECT_NE(location, -1);
location = GPU_shader_get_uniform(shader, "WorldClipPlanes");
EXPECT_NE(location, -1);
location = GPU_shader_get_uniform(shader, "srgbTarget");
EXPECT_NE(location, -1);
location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
EXPECT_NE(location, -1);
location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
EXPECT_NE(location, -1);
location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR);
EXPECT_NE(location, -1);
location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CLIPPLANES);
EXPECT_NE(location, -1);
location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_SRGB_TRANSFORM);
EXPECT_NE(location, -1);
float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
GPU_shader_uniform_4fv(shader, "color", color);
GPU_shader_free(shader);
}
GPU_TEST(shader_block_struct)
} // namespace blender::gpu::tests