GPUShader: GL backend isolation

This commit is contained in:
Clément Foucault 2020-08-14 15:20:35 +02:00
parent df28d2c27e
commit 216d78687d
Notes: blender-bot 2023-02-14 06:17:14 +01:00
Referenced by commit 8948f73784, Fix T81334: Python view-port drawing depth-test regression
Referenced by issue #83203, bgl.glGetUniformLocation()  wrongly always returns -1
Referenced by issue #81334, viewport drawing with gpu module
Referenced by issue #79975, Blender 2.91 crashes with segmentation fault when enabling Sun Position Addon
Referenced by issue #79978, Crashes after start
Referenced by issue #79951, Blender 2.91 Alpha crash related to GPU_shader_create_from_python
20 changed files with 673 additions and 581 deletions

View File

@ -31,8 +31,7 @@
#include "GPU_extensions.h"
#include "GPU_platform.h"
#include "intern/gpu_primitive_private.h"
#include "intern/gpu_shader_private.h"
#include "GPU_shader.h"
#ifdef USE_GPU_SELECT
# include "GPU_select.h"
@ -821,8 +820,8 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
break;
case DRW_UNIFORM_TFEEDBACK_TARGET:
BLI_assert(uni->pvalue && (*use_tfeedback == false));
*use_tfeedback = GPU_shader_transform_feedback_enable(
shgroup->shader, ((GPUVertBuf *)uni->pvalue)->vbo_id);
*use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
((GPUVertBuf *)uni->pvalue));
break;
/* Legacy/Fallback support. */
case DRW_UNIFORM_BASE_INSTANCE:

View File

@ -92,6 +92,7 @@ set(SRC
opengl/gl_batch.cc
opengl/gl_context.cc
opengl/gl_drawlist.cc
opengl/gl_shader.cc
opengl/gl_vertex_array.cc
GPU_attr_binding.h
@ -137,13 +138,14 @@ set(SRC
intern/gpu_primitive_private.h
intern/gpu_private.h
intern/gpu_select_private.h
intern/gpu_shader_private.h
intern/gpu_shader_private.hh
intern/gpu_vertex_format_private.h
opengl/gl_backend.hh
opengl/gl_batch.hh
opengl/gl_context.hh
opengl/gl_drawlist.hh
opengl/gl_shader.hh
opengl/gl_vertex_array.hh
)

View File

@ -29,7 +29,7 @@
extern "C" {
#endif
struct GPUShaderInterface;
struct GPUShader;
void GPU_matrix_reset(void); /* to Identity transform & empty stack */
@ -147,7 +147,7 @@ const float (*GPU_matrix_normal_get(float m[3][3]))[3];
const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3];
/* set uniform values for currently bound shader */
void GPU_matrix_bind(const struct GPUShaderInterface *);
void GPU_matrix_bind(struct GPUShader *shader);
bool GPU_matrix_dirty_get(void); /* since last bind */
/* own working polygon offset */

View File

@ -27,14 +27,19 @@
extern "C" {
#endif
typedef struct GPUShader GPUShader;
struct GPUShaderInterface;
struct GPUTexture;
struct GPUUniformBuffer;
struct GPUVertBuf;
/* GPU Shader
* - only for fragment shaders now
* - must call texture bind before setting a texture as uniform! */
/* TODO(fclem) These members should be private and the
* whole struct should just be an opaque pointer. */
typedef struct GPUShader {
/** Uniform & attribute locations for shader. */
struct GPUShaderInterface *interface;
/** For debugging purpose. */
char name[64];
} GPUShader;
typedef enum eGPUShaderTFBType {
GPU_SHADER_TFB_NONE = 0, /* Transform feedback unsupported. */
@ -63,10 +68,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
const char **tf_names,
const int tf_count,
const char *shader_name);
GPUShader *GPU_shader_load_from_binary(const char *binary,
const int binary_format,
const int binary_len,
const char *shname);
struct GPU_ShaderCreateFromArray_Params {
const char **vert, **geom, **frag, **defs;
};
@ -81,12 +83,12 @@ void GPU_shader_bind(GPUShader *shader);
void GPU_shader_unbind(void);
/* Returns true if transform feedback was successfully enabled. */
bool GPU_shader_transform_feedback_enable(GPUShader *shader, unsigned int vbo_id);
bool GPU_shader_transform_feedback_enable(GPUShader *shader, struct GPUVertBuf *vertbuf);
void GPU_shader_transform_feedback_disable(GPUShader *shader);
int GPU_shader_get_program(GPUShader *shader);
void GPU_shader_set_srgb_uniform(const struct GPUShaderInterface *interface);
void GPU_shader_set_srgb_uniform(GPUShader *shader);
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);

View File

@ -28,6 +28,7 @@
#include "gpu_batch_private.hh"
#include "gpu_context_private.hh"
#include "gpu_drawlist_private.hh"
#include "gpu_shader_private.hh"
namespace blender {
namespace gpu {
@ -43,7 +44,7 @@ class GPUBackend {
virtual Batch *batch_alloc(void) = 0;
virtual DrawList *drawlist_alloc(int list_length) = 0;
// virtual FrameBuffer *framebuffer_alloc(void) = 0;
// virtual Shader *shader_alloc(void) = 0;
virtual Shader *shader_alloc(const char *name) = 0;
// virtual Texture *texture_alloc(void) = 0;
};

View File

@ -39,7 +39,7 @@
#include "gpu_batch_private.hh"
#include "gpu_context_private.hh"
#include "gpu_primitive_private.h"
#include "gpu_shader_private.h"
#include "gpu_shader_private.hh"
#include "gpu_vertex_format_private.h"
#include <limits.h>

View File

@ -35,7 +35,6 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h" /* own include */
#include "GPU_batch_utils.h"
#include "gpu_shader_private.h"
/* -------------------------------------------------------------------- */
/** \name Local Structures

View File

@ -28,7 +28,6 @@
#include "GPU_batch.h"
#include "GPU_batch_utils.h" /* own include */
#include "gpu_shader_private.h"
/* -------------------------------------------------------------------- */
/** \name Polygon Creation (2D)

View File

@ -35,7 +35,7 @@
#include "gpu_attr_binding_private.h"
#include "gpu_context_private.hh"
#include "gpu_primitive_private.h"
#include "gpu_shader_private.h"
#include "gpu_shader_private.hh"
#include "gpu_vertex_format_private.h"
#include <stdlib.h>
@ -145,10 +145,7 @@ GPUVertFormat *immVertexFormat(void)
void immBindShader(GPUShader *shader)
{
#if TRUST_NO_ONE
assert(imm.bound_program == NULL);
assert(glIsProgram(shader->program));
#endif
BLI_assert(imm.bound_program == NULL);
imm.bound_program = shader;
imm.shader_interface = shader->interface;
@ -159,8 +156,8 @@ void immBindShader(GPUShader *shader)
GPU_shader_bind(shader);
get_attr_locations(&imm.vertex_format, &imm.attr_binding, imm.shader_interface);
GPU_matrix_bind(imm.shader_interface);
GPU_shader_set_srgb_uniform(imm.shader_interface);
GPU_matrix_bind(shader);
GPU_shader_set_srgb_uniform(shader);
}
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
@ -375,7 +372,7 @@ static void immDrawSetup(void)
}
if (GPU_matrix_dirty_get()) {
GPU_matrix_bind(imm.shader_interface);
GPU_matrix_bind(imm.bound_program);
}
}

View File

@ -643,13 +643,13 @@ const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3]
return m;
}
void GPU_matrix_bind(const GPUShaderInterface *shaderface)
void GPU_matrix_bind(GPUShader *shader)
{
/* set uniform values to matrix stack values
* call this before a draw call if desired matrices are dirty
* call glUseProgram before this, as glUniform expects program to be bound
*/
const GPUShaderInterface *shaderface = shader->interface;
int32_t MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW);
int32_t P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION);
int32_t MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP);
@ -658,32 +658,30 @@ void GPU_matrix_bind(const GPUShaderInterface *shaderface)
int32_t MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV);
int32_t P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV);
/* XXX(fclem) this works but this assumes shader is unused inside GPU_shader_uniform_vector. */
GPUShader *sh = NULL;
if (MV != -1) {
GPU_shader_uniform_vector(sh, MV, 16, 1, (const float *)GPU_matrix_model_view_get(NULL));
GPU_shader_uniform_vector(shader, MV, 16, 1, (const float *)GPU_matrix_model_view_get(NULL));
}
if (P != -1) {
GPU_shader_uniform_vector(sh, P, 16, 1, (const float *)GPU_matrix_projection_get(NULL));
GPU_shader_uniform_vector(shader, P, 16, 1, (const float *)GPU_matrix_projection_get(NULL));
}
if (MVP != -1) {
GPU_shader_uniform_vector(
sh, MVP, 16, 1, (const float *)GPU_matrix_model_view_projection_get(NULL));
shader, MVP, 16, 1, (const float *)GPU_matrix_model_view_projection_get(NULL));
}
if (N != -1) {
GPU_shader_uniform_vector(sh, N, 9, 1, (const float *)GPU_matrix_normal_get(NULL));
GPU_shader_uniform_vector(shader, N, 9, 1, (const float *)GPU_matrix_normal_get(NULL));
}
if (MV_inv != -1) {
Mat4 m;
GPU_matrix_model_view_get(m);
invert_m4(m);
GPU_shader_uniform_vector(sh, MV_inv, 16, 1, (const float *)m);
GPU_shader_uniform_vector(shader, MV_inv, 16, 1, (const float *)m);
}
if (P_inv != -1) {
Mat4 m;
GPU_matrix_projection_get(m);
invert_m4(m);
GPU_shader_uniform_vector(sh, P_inv, 16, 1, (const float *)m);
GPU_shader_uniform_vector(shader, P_inv, 16, 1, (const float *)m);
}
gpu_matrix_state_active_set_dirty(false);

View File

@ -29,6 +29,7 @@
#include "BLI_string.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
#include "BKE_appdir.h"
#include "BKE_global.h"
@ -42,182 +43,44 @@
#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
#include "gpu_shader_private.h"
#include "gpu_shader_private.hh"
extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[];
/* Adjust these constants as needed. */
#define MAX_DEFINE_LENGTH 256
#define MAX_EXT_DEFINE_LENGTH 512
#ifndef NDEBUG
static uint g_shaderid = 0;
#endif
using namespace blender;
using namespace blender::gpu;
/* -------------------------------------------------------------------- */
/** \name Convenience functions
/** \name Debug functions
* \{ */
static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
void Shader::print_errors(Span<const char *> sources, const char *log)
{
int line = 1;
// int line = 1;
fprintf(stderr, "GPUShader: %s error:\n", task);
// for (int i = 0; i < totcode; i++) {
// const char *c, *pos, *end = code[i] + strlen(code[i]);
for (int i = 0; i < totcode; i++) {
const char *c, *pos, *end = code[i] + strlen(code[i]);
// if (G.debug & G_DEBUG) {
// fprintf(stderr, "===== shader string %d ====\n", i + 1);
if (G.debug & G_DEBUG) {
fprintf(stderr, "===== shader string %d ====\n", i + 1);
c = code[i];
while ((c < end) && (pos = strchr(c, '\n'))) {
fprintf(stderr, "%2d ", line);
fwrite(c, (pos + 1) - c, 1, stderr);
c = pos + 1;
line++;
}
fprintf(stderr, "%s", c);
}
}
// c = code[i];
// while ((c < end) && (pos = strchr(c, '\n'))) {
// fprintf(stderr, "%2d ", line);
// fwrite(c, (pos + 1) - c, 1, stderr);
// c = pos + 1;
// line++;
// }
// fprintf(stderr, "%s", c);
// }
// }
/* TODO display the error lines context. */
fprintf(stderr, "%s\n", log);
}
static const char *gpu_shader_version(void)
{
return "#version 330\n";
}
static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
{
/* enable extensions for features that are not part of our base GLSL version
* don't use an extension for something already available!
*/
if (GLEW_ARB_texture_gather) {
/* There is a bug on older Nvidia GPU where GL_ARB_texture_gather
* is reported to be supported but yield a compile error (see T55802). */
if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) || GLEW_VERSION_4_0) {
strcat(defines, "#extension GL_ARB_texture_gather: enable\n");
/* Some drivers don't agree on GLEW_ARB_texture_gather and the actual support in the
* shader so double check the preprocessor define (see T56544). */
if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) && !GLEW_VERSION_4_0) {
strcat(defines, "#ifdef GL_ARB_texture_gather\n");
strcat(defines, "# define GPU_ARB_texture_gather\n");
strcat(defines, "#endif\n");
}
else {
strcat(defines, "#define GPU_ARB_texture_gather\n");
}
}
}
if (GLEW_ARB_texture_query_lod) {
/* a #version 400 feature, but we use #version 330 maximum so use extension */
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
}
if (GLEW_ARB_shader_draw_parameters) {
strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n");
strcat(defines, "#define GPU_ARB_shader_draw_parameters\n");
}
if (GPU_arb_texture_cube_map_array_is_supported()) {
strcat(defines, "#extension GL_ARB_texture_cube_map_array : enable\n");
strcat(defines, "#define GPU_ARB_texture_cube_map_array\n");
}
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
{
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_ATI\n");
if (GPU_crappy_amd_driver()) {
strcat(defines, "#define GPU_DEPRECATED_AMD_DRIVER\n");
}
}
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_NVIDIA\n");
}
else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_INTEL\n");
}
/* some useful defines to detect OS type */
if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_WIN, GPU_DRIVER_ANY)) {
strcat(defines, "#define OS_WIN\n");
}
else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY)) {
strcat(defines, "#define OS_MAC\n");
}
else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
strcat(defines, "#define OS_UNIX\n");
}
float derivatives_factors[2];
GPU_get_dfdy_factors(derivatives_factors);
if (derivatives_factors[0] == 1.0f) {
strcat(defines, "#define DFDX_SIGN 1.0\n");
}
else {
strcat(defines, "#define DFDX_SIGN -1.0\n");
}
if (derivatives_factors[1] == 1.0f) {
strcat(defines, "#define DFDY_SIGN 1.0\n");
}
else {
strcat(defines, "#define DFDY_SIGN -1.0\n");
}
}
#define DEBUG_SHADER_NONE ""
#define DEBUG_SHADER_VERTEX "vert"
#define DEBUG_SHADER_FRAGMENT "frag"
#define DEBUG_SHADER_GEOMETRY "geom"
/**
* Dump GLSL shaders to disk
*
* This is used for profiling shader performance externally and debug if shader code is correct.
* If called with no code, it simply bumps the shader index, so different shaders for the same
* program share the same index.
*/
static void gpu_dump_shaders(const char **code, const int num_shaders, const char *extension)
{
if ((G.debug & G_DEBUG_GPU_SHADERS) == 0) {
return;
}
/* We use the same shader index for shaders in the same program.
* So we call this function once before calling for the individual shaders. */
static int shader_index = 0;
if (code == NULL) {
shader_index++;
BLI_assert(STREQ(DEBUG_SHADER_NONE, extension));
return;
}
/* Determine the full path of the new shader. */
char shader_path[FILE_MAX];
char file_name[512] = {'\0'};
sprintf(file_name, "%04d.%s", shader_index, extension);
BLI_join_dirfile(shader_path, sizeof(shader_path), BKE_tempdir_session(), file_name);
/* Write shader to disk. */
FILE *f = fopen(shader_path, "w");
if (f == NULL) {
printf("Error writing to file: %s\n", shader_path);
}
for (int j = 0; j < num_shaders; j++) {
fprintf(f, "%s", code[j]);
}
fclose(f);
printf("Shader file written to disk: %s\n", shader_path);
UNUSED_VARS(sources);
}
/** \} */
@ -226,20 +89,149 @@ static void gpu_dump_shaders(const char **code, const int num_shaders, const cha
/** \name Creation / Destruction
* \{ */
GPUShader *GPU_shader_create(const char *vertexcode,
Shader::Shader(const char *sh_name)
{
BLI_strncpy(this->name, sh_name, sizeof(this->name));
}
Shader::~Shader()
{
if (this->interface) {
GPU_shaderinterface_discard(this->interface);
}
}
static void standard_defines(Vector<const char *> &sources)
{
BLI_assert(sources.size() == 0);
/* Version needs to be first. Exact values will be added by implementation. */
sources.append("version");
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
sources.append("#define GPU_ATI\n");
}
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
sources.append("#define GPU_NVIDIA\n");
}
else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
sources.append("#define GPU_INTEL\n");
}
/* some useful defines to detect OS type */
if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_WIN, GPU_DRIVER_ANY)) {
sources.append("#define OS_WIN\n");
}
else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY)) {
sources.append("#define OS_MAC\n");
}
else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
sources.append("#define OS_UNIX\n");
}
if (GPU_crappy_amd_driver()) {
sources.append("#define GPU_DEPRECATED_AMD_DRIVER\n");
}
}
GPUShader *GPU_shader_create_ex(const char *vertcode,
const char *fragcode,
const char *geomcode,
const char *libcode,
const char *defines,
const eGPUShaderTFBType tf_type,
const char **tf_names,
const int tf_count,
const char *shname)
{
/* At least a vertex shader and a fragment shader are required. */
BLI_assert((fragcode != NULL) && (vertcode != NULL));
Shader *shader = GPUBackend::get()->shader_alloc(shname);
if (vertcode) {
Vector<const char *> sources;
standard_defines(sources);
sources.append("#define GPU_VERTEX_SHADER\n");
sources.append("#define IN_OUT out\n");
if (geomcode) {
sources.append("#define USE_GEOMETRY_SHADER\n");
}
if (defines) {
sources.append(defines);
}
sources.append(vertcode);
shader->vertex_shader_from_glsl(sources);
}
if (fragcode) {
Vector<const char *> sources;
standard_defines(sources);
sources.append("#define GPU_FRAGMENT_SHADER\n");
sources.append("#define IN_OUT in\n");
if (geomcode) {
sources.append("#define USE_GEOMETRY_SHADER\n");
}
if (defines) {
sources.append(defines);
}
if (libcode) {
sources.append(libcode);
}
sources.append(fragcode);
shader->fragment_shader_from_glsl(sources);
}
if (geomcode) {
Vector<const char *> sources;
standard_defines(sources);
sources.append("#define GPU_GEOMETRY_SHADER\n");
if (defines) {
sources.append(defines);
}
sources.append(geomcode);
shader->geometry_shader_from_glsl(sources);
}
if (tf_names != NULL && 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 NULL;
};
return static_cast<GPUShader *>(shader);
}
void GPU_shader_free(GPUShader *shader)
{
delete static_cast<Shader *>(shader);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Creation utils
* \{ */
GPUShader *GPU_shader_create(const char *vertcode,
const char *fragcode,
const char *geocode,
const char *geomcode,
const char *libcode,
const char *defines,
const char *shname)
{
return GPU_shader_create_ex(
vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, shname);
vertcode, fragcode, geomcode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, shname);
}
GPUShader *GPU_shader_create_from_python(const char *vertexcode,
GPUShader *GPU_shader_create_from_python(const char *vertcode,
const char *fragcode,
const char *geocode,
const char *geomcode,
const char *libcode,
const char *defines)
{
@ -253,241 +245,12 @@ GPUShader *GPU_shader_create_from_python(const char *vertexcode,
}
GPUShader *sh = GPU_shader_create_ex(
vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, NULL);
vertcode, fragcode, geomcode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, NULL);
MEM_SAFE_FREE(libcodecat);
return sh;
}
GPUShader *GPU_shader_create_ex(const char *vertexcode,
const char *fragcode,
const char *geocode,
const char *libcode,
const char *defines,
const eGPUShaderTFBType tf_type,
const char **tf_names,
const int tf_count,
const char *shname)
{
GLint status;
GLchar log[5000];
GLsizei length = 0;
GPUShader *shader;
char standard_defines[MAX_DEFINE_LENGTH] = "";
char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
shader = (GPUShader *)MEM_callocN(sizeof(GPUShader), "GPUShader");
gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE);
#ifndef NDEBUG
BLI_snprintf(shader->name, sizeof(shader->name), "%s_%u", shname, g_shaderid++);
#else
UNUSED_VARS(shname);
#endif
/* At least a vertex shader and a fragment shader are required. */
BLI_assert((fragcode != NULL) && (vertexcode != NULL));
if (vertexcode) {
shader->vertex = glCreateShader(GL_VERTEX_SHADER);
}
if (fragcode) {
shader->fragment = glCreateShader(GL_FRAGMENT_SHADER);
}
if (geocode) {
shader->geometry = glCreateShader(GL_GEOMETRY_SHADER);
}
shader->program = glCreateProgram();
if (!shader->program || (vertexcode && !shader->vertex) || (fragcode && !shader->fragment) ||
(geocode && !shader->geometry)) {
fprintf(stderr, "GPUShader, object creation failed.\n");
GPU_shader_free(shader);
return NULL;
}
gpu_shader_standard_defines(standard_defines);
gpu_shader_standard_extensions(standard_extensions);
if (vertexcode) {
const char *source[7];
/* custom limit, may be too small, beware */
int num_source = 0;
source[num_source++] = gpu_shader_version();
source[num_source++] =
"#define GPU_VERTEX_SHADER\n"
"#define IN_OUT out\n";
source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
if (geocode) {
source[num_source++] = "#define USE_GEOMETRY_SHADER\n";
}
if (defines) {
source[num_source++] = defines;
}
source[num_source++] = vertexcode;
gpu_dump_shaders(source, num_source, DEBUG_SHADER_VERTEX);
glAttachShader(shader->program, shader->vertex);
glShaderSource(shader->vertex, num_source, source, NULL);
glCompileShader(shader->vertex);
glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status);
if (!status) {
glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log);
shader_print_errors("compile", log, source, num_source);
GPU_shader_free(shader);
return NULL;
}
}
if (fragcode) {
const char *source[8];
int num_source = 0;
source[num_source++] = gpu_shader_version();
source[num_source++] =
"#define GPU_FRAGMENT_SHADER\n"
"#define IN_OUT in\n";
source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
if (geocode) {
source[num_source++] = "#define USE_GEOMETRY_SHADER\n";
}
if (defines) {
source[num_source++] = defines;
}
if (libcode) {
source[num_source++] = libcode;
}
source[num_source++] = fragcode;
gpu_dump_shaders(source, num_source, DEBUG_SHADER_FRAGMENT);
glAttachShader(shader->program, shader->fragment);
glShaderSource(shader->fragment, num_source, source, NULL);
glCompileShader(shader->fragment);
glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status);
if (!status) {
glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log);
shader_print_errors("compile", log, source, num_source);
GPU_shader_free(shader);
return NULL;
}
}
if (geocode) {
const char *source[6];
int num_source = 0;
source[num_source++] = gpu_shader_version();
source[num_source++] = "#define GPU_GEOMETRY_SHADER\n";
source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
if (defines) {
source[num_source++] = defines;
}
source[num_source++] = geocode;
gpu_dump_shaders(source, num_source, DEBUG_SHADER_GEOMETRY);
glAttachShader(shader->program, shader->geometry);
glShaderSource(shader->geometry, num_source, source, NULL);
glCompileShader(shader->geometry);
glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status);
if (!status) {
glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log);
shader_print_errors("compile", log, source, num_source);
GPU_shader_free(shader);
return NULL;
}
}
if (tf_names != NULL) {
glTransformFeedbackVaryings(shader->program, tf_count, tf_names, GL_INTERLEAVED_ATTRIBS);
/* Primitive type must be setup */
BLI_assert(tf_type != GPU_SHADER_TFB_NONE);
shader->feedback_transform_type = tf_type;
}
glLinkProgram(shader->program);
glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
if (!status) {
glGetProgramInfoLog(shader->program, sizeof(log), &length, log);
/* print attached shaders in pipeline order */
if (defines) {
shader_print_errors("linking", log, &defines, 1);
}
if (vertexcode) {
shader_print_errors("linking", log, &vertexcode, 1);
}
if (geocode) {
shader_print_errors("linking", log, &geocode, 1);
}
if (libcode) {
shader_print_errors("linking", log, &libcode, 1);
}
if (fragcode) {
shader_print_errors("linking", log, &fragcode, 1);
}
GPU_shader_free(shader);
return NULL;
}
glUseProgram(shader->program);
shader->interface = GPU_shaderinterface_create(shader->program);
return shader;
}
#undef DEBUG_SHADER_GEOMETRY
#undef DEBUG_SHADER_FRAGMENT
#undef DEBUG_SHADER_VERTEX
#undef DEBUG_SHADER_NONE
void GPU_shader_free(GPUShader *shader)
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
BLI_assert(GPU_context_active_get() != NULL);
#endif
BLI_assert(shader);
if (shader->vertex) {
glDeleteShader(shader->vertex);
}
if (shader->geometry) {
glDeleteShader(shader->geometry);
}
if (shader->fragment) {
glDeleteShader(shader->fragment);
}
if (shader->program) {
glDeleteProgram(shader->program);
}
if (shader->interface) {
GPU_shaderinterface_discard(shader->interface);
}
MEM_freeN(shader);
}
static const char *string_join_array_maybe_alloc(const char **str_arr, bool *r_is_alloc)
{
bool is_alloc = false;
@ -563,21 +326,21 @@ struct GPUShader *GPU_shader_create_from_arrays_impl(
/** \name Binding
* \{ */
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_bind(GPUShader *gpu_shader)
{
BLI_assert(shader && shader->program);
Shader *shader = static_cast<Shader *>(gpu_shader);
GPUContext *ctx = GPU_context_active_get();
if (ctx->shader != shader) {
ctx->shader = shader;
glUseProgram(shader->program);
GPU_matrix_bind(shader->interface);
GPU_shader_set_srgb_uniform(shader->interface);
shader->bind();
GPU_matrix_bind(shader);
GPU_shader_set_srgb_uniform(shader);
}
if (GPU_matrix_dirty_get()) {
GPU_matrix_bind(shader->interface);
GPU_matrix_bind(shader);
}
}
@ -585,8 +348,10 @@ void GPU_shader_unbind(void)
{
#ifndef NDEBUG
GPUContext *ctx = GPU_context_active_get();
if (ctx->shader) {
static_cast<Shader *>(ctx->shader)->unbind();
}
ctx->shader = NULL;
glUseProgram(0);
#endif
}
@ -594,34 +359,18 @@ void GPU_shader_unbind(void)
/* -------------------------------------------------------------------- */
/** \name Transform feedback
*
* TODO(fclem) Should be replaced by compute shaders.
* \{ */
bool GPU_shader_transform_feedback_enable(GPUShader *shader, uint vbo_id)
bool GPU_shader_transform_feedback_enable(GPUShader *shader, GPUVertBuf *vertbuf)
{
if (shader->feedback_transform_type == GPU_SHADER_TFB_NONE) {
return false;
}
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo_id);
switch (shader->feedback_transform_type) {
case GPU_SHADER_TFB_POINTS:
glBeginTransformFeedback(GL_POINTS);
return true;
case GPU_SHADER_TFB_LINES:
glBeginTransformFeedback(GL_LINES);
return true;
case GPU_SHADER_TFB_TRIANGLES:
glBeginTransformFeedback(GL_TRIANGLES);
return true;
default:
return false;
}
return static_cast<Shader *>(shader)->transform_feedback_enable(vertbuf);
}
void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader))
void GPU_shader_transform_feedback_disable(GPUShader *shader)
{
glEndTransformFeedback();
static_cast<Shader *>(shader)->transform_feedback_disable();
}
/** \} */
@ -632,49 +381,42 @@ void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader))
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
{
BLI_assert(shader && shader->program);
const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name);
return uniform ? uniform->location : -1;
}
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
{
BLI_assert(shader && shader->program);
return GPU_shaderinterface_uniform_builtin(shader->interface,
static_cast<GPUUniformBuiltin>(builtin));
}
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
{
BLI_assert(shader && shader->program);
return GPU_shaderinterface_block_builtin(shader->interface,
static_cast<GPUUniformBlockBuiltin>(builtin));
}
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
{
BLI_assert(shader && shader->program);
const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
return ubo ? ubo->location : -1;
}
int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name)
{
BLI_assert(shader && shader->program);
const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
return ubo ? ubo->binding : -1;
}
int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
{
BLI_assert(shader && shader->program);
const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name);
return tex ? tex->binding : -1;
}
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
{
BLI_assert(shader && shader->program);
const GPUShaderInput *attr = GPU_shaderinterface_attr(shader->interface, name);
return attr ? attr->location : -1;
}
@ -686,9 +428,10 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name)
* \{ */
/* Clement : Temp */
int GPU_shader_get_program(GPUShader *shader)
int GPU_shader_get_program(GPUShader *UNUSED(shader))
{
return (int)shader->program;
/* TODO fixme */
return (int)0;
}
/** \} */
@ -698,57 +441,15 @@ int GPU_shader_get_program(GPUShader *shader)
* \{ */
void GPU_shader_uniform_vector(
GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value)
GPUShader *shader, int loc, int len, int arraysize, const float *value)
{
if (location == -1 || value == NULL) {
return;
}
switch (length) {
case 1:
glUniform1fv(location, arraysize, value);
break;
case 2:
glUniform2fv(location, arraysize, value);
break;
case 3:
glUniform3fv(location, arraysize, value);
break;
case 4:
glUniform4fv(location, arraysize, value);
break;
case 9:
glUniformMatrix3fv(location, arraysize, 0, value);
break;
case 16:
glUniformMatrix4fv(location, arraysize, 0, value);
break;
default:
BLI_assert(0);
break;
}
static_cast<Shader *>(shader)->uniform_float(loc, len, arraysize, value);
}
void GPU_shader_uniform_vector_int(
GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
GPUShader *shader, int loc, int len, int arraysize, const int *value)
{
switch (length) {
case 1:
glUniform1iv(location, arraysize, value);
break;
case 2:
glUniform2iv(location, arraysize, value);
break;
case 3:
glUniform3iv(location, arraysize, value);
break;
case 4:
glUniform4iv(location, arraysize, value);
break;
default:
BLI_assert(0);
break;
}
static_cast<Shader *>(shader)->uniform_int(loc, len, arraysize, value);
}
void GPU_shader_uniform_int(GPUShader *shader, int location, int value)
@ -851,11 +552,11 @@ void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, cons
static int g_shader_builtin_srgb_transform = 0;
void GPU_shader_set_srgb_uniform(const GPUShaderInterface *interface)
void GPU_shader_set_srgb_uniform(GPUShader *shader)
{
int32_t loc = GPU_shaderinterface_uniform_builtin(interface, GPU_UNIFORM_SRGB_TRANSFORM);
int32_t loc = GPU_shaderinterface_uniform_builtin(shader->interface, GPU_UNIFORM_SRGB_TRANSFORM);
if (loc != -1) {
glUniform1i(loc, g_shader_builtin_srgb_transform);
GPU_shader_uniform_vector_int(shader, loc, 1, 1, &g_shader_builtin_srgb_transform);
}
}

View File

@ -42,8 +42,6 @@
#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
#include "gpu_shader_private.h"
/* Adjust these constants as needed. */
#define MAX_DEFINE_LENGTH 256
#define MAX_EXT_DEFINE_LENGTH 512

View File

@ -1,54 +0,0 @@
/*
* 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.
*/
/** \file
* \ingroup gpu
*/
#pragma once
#include "GPU_shader_interface.h"
#ifdef __cplusplus
extern "C" {
#endif
struct GPUShader {
/** Handle for full program (links shader stages below). */
GLuint program;
/** Handle for vertex shader. */
GLuint vertex;
/** Handle for geometry shader. */
GLuint geometry;
/** Handle for fragment shader. */
GLuint fragment;
/** Cached uniform & attribute interface for shader. */
GPUShaderInterface *interface;
int feedback_transform_type;
#ifndef NDEBUG
char name[64];
#endif
};
/* XXX do not use it. Special hack to use OCIO with batch API. */
GPUShader *immGetShader(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,61 @@
/*
* 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.
*/
/** \file
* \ingroup gpu
*/
#pragma once
#include "BLI_span.hh"
#include "GPU_shader.h"
#include "GPU_shader_interface.h"
#include "GPU_vertex_buffer.h"
namespace blender {
namespace gpu {
class Shader : public GPUShader {
public:
Shader(const char *name);
virtual ~Shader();
virtual void vertex_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual void geometry_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual void fragment_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual bool finalize(void) = 0;
virtual void transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type) = 0;
virtual bool transform_feedback_enable(GPUVertBuf *) = 0;
virtual void transform_feedback_disable(void) = 0;
virtual void bind(void) = 0;
virtual void unbind(void) = 0;
virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0;
virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0;
protected:
void print_errors(Span<const char *> sources, const char *log);
};
} // namespace gpu
} // namespace blender
/* XXX do not use it. Special hack to use OCIO with batch API. */
GPUShader *immGetShader(void);

View File

@ -33,7 +33,6 @@
#include "BLI_utildefines.h"
#include "GPU_shader.h"
#include "gpu_shader_private.h"
#define PACK_DEBUG 0
@ -480,6 +479,8 @@ static void get_fetch_mode_and_comp_type(int gl_type,
void GPU_vertformat_from_shader(GPUVertFormat *format, const GPUShader *shader)
{
UNUSED_VARS(format, shader);
#if 0 /* TODO (fclem) port to GLShader */
GPU_vertformat_clear(format);
GPUVertAttr *attr = &format->attrs[0];
@ -512,4 +513,5 @@ void GPU_vertformat_from_shader(GPUVertFormat *format, const GPUShader *shader)
attr->comp_type = comp_type;
attr += 1;
}
#endif
}

View File

@ -30,6 +30,7 @@
#include "gl_batch.hh"
#include "gl_context.hh"
#include "gl_drawlist.hh"
#include "gl_shader.hh"
namespace blender {
namespace gpu {
@ -54,6 +55,11 @@ class GLBackend : public GPUBackend {
return new GLDrawList(list_length);
};
Shader *shader_alloc(const char *name)
{
return new GLShader(name);
};
/* TODO remove */
void buf_free(GLuint buf_id);
void tex_free(GLuint tex_id);

View File

@ -33,7 +33,6 @@
#include "gpu_batch_private.hh"
#include "gpu_primitive_private.h"
#include "gpu_shader_private.h"
#include "gl_batch.hh"
#include "gl_context.hh"

View File

@ -0,0 +1,302 @@
/*
* 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) 2020 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup gpu
*/
#include "BLI_string.h"
#include "GPU_extensions.h"
#include "GPU_platform.h"
#include "gl_shader.hh"
using namespace blender;
using namespace blender::gpu;
/* -------------------------------------------------------------------- */
/** \name Creation / Destruction
* \{ */
GLShader::GLShader(const char *name) : Shader(name)
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
BLI_assert(GPU_context_active_get() != NULL);
#endif
shader_program_ = glCreateProgram();
}
GLShader::~GLShader(void)
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
BLI_assert(GPU_context_active_get() != NULL);
#endif
/* Invalid handles are silently ignored. */
glDeleteShader(vert_shader_);
glDeleteShader(geom_shader_);
glDeleteShader(frag_shader_);
glDeleteProgram(shader_program_);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Shader stage creation
* \{ */
char *GLShader::glsl_patch_get(void)
{
/** Used for shader patching. Init once. */
static char patch[512] = "\0";
if (patch[0] != '\0') {
return patch;
}
size_t slen = 0;
/* Version need to go first. */
STR_CONCAT(patch, slen, "#version 330\n");
/* Enable extensions for features that are not part of our base GLSL version
* don't use an extension for something already available! */
if (GLEW_ARB_texture_gather) {
/* There is a bug on older Nvidia GPU where GL_ARB_texture_gather
* is reported to be supported but yield a compile error (see T55802). */
if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) || GLEW_VERSION_4_0) {
STR_CONCAT(patch, slen, "#extension GL_ARB_texture_gather: enable\n");
/* Some drivers don't agree on GLEW_ARB_texture_gather and the actual support in the
* shader so double check the preprocessor define (see T56544). */
if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) && !GLEW_VERSION_4_0) {
STR_CONCAT(patch, slen, "#ifdef GL_ARB_texture_gather\n");
STR_CONCAT(patch, slen, "# define GPU_ARB_texture_gather\n");
STR_CONCAT(patch, slen, "#endif\n");
}
else {
STR_CONCAT(patch, slen, "#define GPU_ARB_texture_gather\n");
}
}
}
if (GLEW_ARB_shader_draw_parameters) {
STR_CONCAT(patch, slen, "#extension GL_ARB_shader_draw_parameters : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_shader_draw_parameters\n");
}
if (GPU_arb_texture_cube_map_array_is_supported()) {
STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n");
}
/* Derivative sign can change depending on implementation. */
float derivatives[2];
GPU_get_dfdy_factors(derivatives);
STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", derivatives[0]);
STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", derivatives[1]);
BLI_assert(slen < sizeof(patch));
return patch;
}
/* Create, compile and attach the shader stage to the shader program. */
GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources)
{
GLuint shader = glCreateShader(gl_stage);
if (shader == 0) {
fprintf(stderr, "GLShader: Error: Could not create shader object.");
return 0;
}
/* Patch the shader code using the first source slot. */
sources[0] = glsl_patch_get();
glShaderSource(shader, sources.size(), sources.data(), NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (!status) {
char log[5000];
glGetShaderInfoLog(shader, sizeof(log), NULL, log);
this->print_errors(sources, log);
glDeleteShader(shader);
return 0;
}
glAttachShader(shader_program_, shader);
return shader;
}
void GLShader::vertex_shader_from_glsl(MutableSpan<const char *> sources)
{
vert_shader_ = this->create_shader_stage(GL_VERTEX_SHADER, sources);
}
void GLShader::geometry_shader_from_glsl(MutableSpan<const char *> sources)
{
geom_shader_ = this->create_shader_stage(GL_GEOMETRY_SHADER, sources);
}
void GLShader::fragment_shader_from_glsl(MutableSpan<const char *> sources)
{
frag_shader_ = this->create_shader_stage(GL_FRAGMENT_SHADER, sources);
}
bool GLShader::finalize(void)
{
glLinkProgram(shader_program_);
GLint status;
glGetProgramiv(shader_program_, GL_LINK_STATUS, &status);
if (!status) {
char log[5000];
glGetProgramInfoLog(shader_program_, sizeof(log), NULL, log);
fprintf(stderr, "\nLinking Error:\n\n%s", log);
return false;
}
/* TODO(fclem) We need this to modify the image binding points using glUniform.
* This could be avoided using glProgramUniform in GL 4.1. */
glUseProgram(shader_program_);
interface = GPU_shaderinterface_create(shader_program_);
return true;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Binding
* \{ */
void GLShader::bind(void)
{
BLI_assert(shader_program_ != 0);
glUseProgram(shader_program_);
}
void GLShader::unbind(void)
{
#ifndef NDEBUG
glUseProgram(0);
#endif
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform feedback
*
* TODO(fclem) Should be replaced by compute shaders.
* \{ */
/* Should be called before linking. */
void GLShader::transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type)
{
glTransformFeedbackVaryings(
shader_program_, name_list.size(), name_list.data(), GL_INTERLEAVED_ATTRIBS);
transform_feedback_type_ = geom_type;
}
bool GLShader::transform_feedback_enable(GPUVertBuf *buf)
{
if (transform_feedback_type_ == GPU_SHADER_TFB_NONE) {
return false;
}
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(void)
{
glEndTransformFeedback();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Uniforms setters
* \{ */
void GLShader::uniform_float(int location, int comp_len, int array_size, const float *data)
{
switch (comp_len) {
case 1:
glUniform1fv(location, array_size, data);
break;
case 2:
glUniform2fv(location, array_size, data);
break;
case 3:
glUniform3fv(location, array_size, data);
break;
case 4:
glUniform4fv(location, array_size, data);
break;
case 9:
glUniformMatrix3fv(location, array_size, 0, data);
break;
case 16:
glUniformMatrix4fv(location, array_size, 0, data);
break;
default:
BLI_assert(0);
break;
}
}
void GLShader::uniform_int(int location, int comp_len, int array_size, const int *data)
{
switch (comp_len) {
case 1:
glUniform1iv(location, array_size, data);
break;
case 2:
glUniform2iv(location, array_size, data);
break;
case 3:
glUniform3iv(location, array_size, data);
break;
case 4:
glUniform4iv(location, array_size, data);
break;
default:
BLI_assert(0);
break;
}
}
/** \} */

View File

@ -0,0 +1,79 @@
/*
* 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) 2020 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup gpu
*
* GPUDrawList is an API to do lots of similar draw-calls very fast using
* multi-draw-indirect. There is a fallback if the feature is not supported.
*/
#pragma once
#include "MEM_guardedalloc.h"
#include "glew-mx.h"
#include "gpu_shader_private.hh"
namespace blender {
namespace gpu {
class GLShader : public Shader {
private:
/** Handle for full program (links shader stages below). */
GLuint shader_program_ = 0;
GLuint vert_shader_ = 0;
GLuint geom_shader_ = 0;
GLuint frag_shader_ = 0;
eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
public:
GLShader(const char *name);
~GLShader();
/* Return true on success. */
void vertex_shader_from_glsl(MutableSpan<const char *> sources) override;
void geometry_shader_from_glsl(MutableSpan<const char *> sources) override;
void fragment_shader_from_glsl(MutableSpan<const char *> sources) override;
bool finalize(void) override;
void transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type);
bool transform_feedback_enable(GPUVertBuf *buf) override;
void transform_feedback_disable(void) override;
void bind(void) override;
void unbind(void) override;
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
private:
char *glsl_patch_get(void);
GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources);
MEM_CXX_CLASS_ALLOC_FUNCS("GLShader");
};
} // namespace gpu
} // namespace blender

View File

@ -604,7 +604,8 @@ PyDoc_STRVAR(
" ``GPU_ATI``, ``GPU_NVIDIA`` and ``GPU_INTEL``.\n"
"\n"
" The following extensions are enabled by default if supported by the GPU:\n"
" ``GL_ARB_texture_gather`` and ``GL_ARB_texture_query_lod``.\n"
" ``GL_ARB_texture_gather``, ``GL_ARB_texture_cube_map_array`` and "
"``GL_ARB_shader_draw_parameters``.\n"
"\n"
" To debug shaders, use the --debug-gpu-shaders command line option"
" to see full GLSL shader compilation and linking errors.\n"