GPUShaderInterface: GL backend isolation
This commit is contained in:
@@ -93,6 +93,7 @@ set(SRC
|
|||||||
opengl/gl_context.cc
|
opengl/gl_context.cc
|
||||||
opengl/gl_drawlist.cc
|
opengl/gl_drawlist.cc
|
||||||
opengl/gl_shader.cc
|
opengl/gl_shader.cc
|
||||||
|
opengl/gl_shader_interface.cc
|
||||||
opengl/gl_state.cc
|
opengl/gl_state.cc
|
||||||
opengl/gl_vertex_array.cc
|
opengl/gl_vertex_array.cc
|
||||||
|
|
||||||
@@ -119,7 +120,6 @@ set(SRC
|
|||||||
GPU_primitive.h
|
GPU_primitive.h
|
||||||
GPU_select.h
|
GPU_select.h
|
||||||
GPU_shader.h
|
GPU_shader.h
|
||||||
GPU_shader_interface.h
|
|
||||||
GPU_state.h
|
GPU_state.h
|
||||||
GPU_texture.h
|
GPU_texture.h
|
||||||
GPU_uniformbuffer.h
|
GPU_uniformbuffer.h
|
||||||
@@ -140,6 +140,7 @@ set(SRC
|
|||||||
intern/gpu_private.h
|
intern/gpu_private.h
|
||||||
intern/gpu_select_private.h
|
intern/gpu_select_private.h
|
||||||
intern/gpu_shader_private.hh
|
intern/gpu_shader_private.hh
|
||||||
|
intern/gpu_shader_interface.hh
|
||||||
intern/gpu_state_private.hh
|
intern/gpu_state_private.hh
|
||||||
intern/gpu_vertex_format_private.h
|
intern/gpu_vertex_format_private.h
|
||||||
|
|
||||||
@@ -148,6 +149,7 @@ set(SRC
|
|||||||
opengl/gl_context.hh
|
opengl/gl_context.hh
|
||||||
opengl/gl_drawlist.hh
|
opengl/gl_drawlist.hh
|
||||||
opengl/gl_shader.hh
|
opengl/gl_shader.hh
|
||||||
|
opengl/gl_shader_interface.hh
|
||||||
opengl/gl_state.hh
|
opengl/gl_state.hh
|
||||||
opengl/gl_vertex_array.hh
|
opengl/gl_vertex_array.hh
|
||||||
)
|
)
|
||||||
|
@@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
#include "GPU_batch.h"
|
#include "GPU_batch.h"
|
||||||
#include "GPU_common.h"
|
#include "GPU_common.h"
|
||||||
#include "GPU_shader_interface.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@@ -29,7 +29,6 @@
|
|||||||
#include "GPU_immediate_util.h"
|
#include "GPU_immediate_util.h"
|
||||||
#include "GPU_primitive.h"
|
#include "GPU_primitive.h"
|
||||||
#include "GPU_shader.h"
|
#include "GPU_shader.h"
|
||||||
#include "GPU_shader_interface.h"
|
|
||||||
#include "GPU_texture.h"
|
#include "GPU_texture.h"
|
||||||
#include "GPU_vertex_format.h"
|
#include "GPU_vertex_format.h"
|
||||||
|
|
||||||
|
@@ -27,7 +27,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct GPUShaderInterface;
|
|
||||||
struct GPUTexture;
|
struct GPUTexture;
|
||||||
struct GPUUniformBuffer;
|
struct GPUUniformBuffer;
|
||||||
struct GPUVertBuf;
|
struct GPUVertBuf;
|
||||||
@@ -35,8 +34,6 @@ struct GPUVertBuf;
|
|||||||
/* TODO(fclem) These members should be private and the
|
/* TODO(fclem) These members should be private and the
|
||||||
* whole struct should just be an opaque pointer. */
|
* whole struct should just be an opaque pointer. */
|
||||||
typedef struct GPUShader {
|
typedef struct GPUShader {
|
||||||
/** Uniform & attribute locations for shader. */
|
|
||||||
struct GPUShaderInterface *interface;
|
|
||||||
/** For debugging purpose. */
|
/** For debugging purpose. */
|
||||||
char name[64];
|
char name[64];
|
||||||
} GPUShader;
|
} GPUShader;
|
||||||
@@ -90,6 +87,41 @@ void GPU_shader_transform_feedback_disable(GPUShader *shader);
|
|||||||
|
|
||||||
int GPU_shader_get_program(GPUShader *shader);
|
int GPU_shader_get_program(GPUShader *shader);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */
|
||||||
|
GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */
|
||||||
|
GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */
|
||||||
|
GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */
|
||||||
|
GPU_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */
|
||||||
|
GPU_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */
|
||||||
|
|
||||||
|
GPU_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */
|
||||||
|
GPU_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */
|
||||||
|
GPU_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */
|
||||||
|
GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */
|
||||||
|
GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
|
||||||
|
|
||||||
|
GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
|
||||||
|
GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */
|
||||||
|
GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
|
||||||
|
|
||||||
|
GPU_UNIFORM_COLOR, /* vec4 color */
|
||||||
|
GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
|
||||||
|
GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
|
||||||
|
GPU_UNIFORM_RESOURCE_ID, /* int resourceId */
|
||||||
|
GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */
|
||||||
|
|
||||||
|
GPU_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */
|
||||||
|
} GPUUniformBuiltin;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */
|
||||||
|
GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */
|
||||||
|
GPU_UNIFORM_BLOCK_INFO, /* infoBlock */
|
||||||
|
|
||||||
|
GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */
|
||||||
|
} GPUUniformBlockBuiltin;
|
||||||
|
|
||||||
void GPU_shader_set_srgb_uniform(GPUShader *shader);
|
void GPU_shader_set_srgb_uniform(GPUShader *shader);
|
||||||
|
|
||||||
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
|
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
|
||||||
@@ -123,8 +155,6 @@ void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, cons
|
|||||||
|
|
||||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
|
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
|
||||||
|
|
||||||
char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len);
|
|
||||||
|
|
||||||
void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear);
|
void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear);
|
||||||
|
|
||||||
/* Builtin/Non-generated shaders */
|
/* Builtin/Non-generated shaders */
|
||||||
|
@@ -1,117 +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.
|
|
||||||
*
|
|
||||||
* The Original Code is Copyright (C) 2016 by Mike Erwin.
|
|
||||||
* All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
* \ingroup gpu
|
|
||||||
*
|
|
||||||
* GPU shader interface (C --> GLSL)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "GPU_common.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */
|
|
||||||
GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */
|
|
||||||
GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */
|
|
||||||
GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */
|
|
||||||
GPU_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */
|
|
||||||
GPU_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */
|
|
||||||
|
|
||||||
GPU_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */
|
|
||||||
GPU_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */
|
|
||||||
GPU_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */
|
|
||||||
GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */
|
|
||||||
GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
|
|
||||||
|
|
||||||
GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
|
|
||||||
GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */
|
|
||||||
GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
|
|
||||||
|
|
||||||
GPU_UNIFORM_COLOR, /* vec4 color */
|
|
||||||
GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
|
|
||||||
GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
|
|
||||||
GPU_UNIFORM_RESOURCE_ID, /* int resourceId */
|
|
||||||
GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */
|
|
||||||
|
|
||||||
GPU_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */
|
|
||||||
} GPUUniformBuiltin;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */
|
|
||||||
GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */
|
|
||||||
GPU_UNIFORM_BLOCK_INFO, /* infoBlock */
|
|
||||||
|
|
||||||
GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */
|
|
||||||
} GPUUniformBlockBuiltin;
|
|
||||||
|
|
||||||
typedef struct GPUShaderInput {
|
|
||||||
uint32_t name_offset;
|
|
||||||
uint32_t name_hash;
|
|
||||||
int32_t location;
|
|
||||||
/** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attribs. */
|
|
||||||
int32_t binding;
|
|
||||||
} GPUShaderInput;
|
|
||||||
|
|
||||||
#define GPU_SHADERINTERFACE_REF_ALLOC_COUNT 16
|
|
||||||
|
|
||||||
typedef struct GPUShaderInterface {
|
|
||||||
/** Buffer containing all inputs names separated by '\0'. */
|
|
||||||
char *name_buffer;
|
|
||||||
/** Reference to GPUBatches using this interface */
|
|
||||||
void **batches;
|
|
||||||
uint batches_len;
|
|
||||||
/** Input counts. */
|
|
||||||
uint attribute_len;
|
|
||||||
uint ubo_len;
|
|
||||||
uint uniform_len;
|
|
||||||
/** Enabled bindpoints that needs to be fed with data. */
|
|
||||||
uint16_t enabled_attr_mask;
|
|
||||||
uint16_t enabled_ubo_mask;
|
|
||||||
uint64_t enabled_tex_mask;
|
|
||||||
/** Opengl Location of builtin uniforms. Fast access, no lookup needed. */
|
|
||||||
int32_t builtins[GPU_NUM_UNIFORMS];
|
|
||||||
int32_t builtin_blocks[GPU_NUM_UNIFORM_BLOCKS];
|
|
||||||
/** Flat array. In this order: Attributes, Ubos, Uniforms. */
|
|
||||||
GPUShaderInput inputs[0];
|
|
||||||
} GPUShaderInterface;
|
|
||||||
|
|
||||||
GPUShaderInterface *GPU_shaderinterface_create(int32_t program_id);
|
|
||||||
void GPU_shaderinterface_discard(GPUShaderInterface *);
|
|
||||||
|
|
||||||
const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *, const char *name);
|
|
||||||
int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface,
|
|
||||||
GPUUniformBuiltin builtin);
|
|
||||||
int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface,
|
|
||||||
GPUUniformBlockBuiltin builtin);
|
|
||||||
const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *, const char *name);
|
|
||||||
const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *, const char *name);
|
|
||||||
|
|
||||||
/* keep track of batches using this interface */
|
|
||||||
void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *interface, void *cache);
|
|
||||||
void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *interface, void *cache);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@@ -61,9 +61,7 @@ static void write_attr_location(GPUAttrBinding *binding, uint a_idx, uint locati
|
|||||||
binding->enabled_bits |= 1 << a_idx;
|
binding->enabled_bits |= 1 << a_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_attr_locations(const GPUVertFormat *format,
|
void get_attr_locations(const GPUVertFormat *format, GPUAttrBinding *binding, GPUShader *shader)
|
||||||
GPUAttrBinding *binding,
|
|
||||||
const GPUShaderInterface *shaderface)
|
|
||||||
{
|
{
|
||||||
AttrBinding_clear(binding);
|
AttrBinding_clear(binding);
|
||||||
|
|
||||||
@@ -71,13 +69,12 @@ void get_attr_locations(const GPUVertFormat *format,
|
|||||||
const GPUVertAttr *a = &format->attrs[a_idx];
|
const GPUVertAttr *a = &format->attrs[a_idx];
|
||||||
for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
|
for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
|
||||||
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
|
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
|
||||||
const GPUShaderInput *input = GPU_shaderinterface_attr(shaderface, name);
|
int loc = GPU_shader_get_attribute(shader, name);
|
||||||
#if TRUST_NO_ONE
|
|
||||||
assert(input != NULL);
|
|
||||||
/* TODO: make this a recoverable runtime error?
|
/* TODO: make this a recoverable runtime error?
|
||||||
* indicates mismatch between vertex format and program. */
|
* indicates mismatch between vertex format and program. */
|
||||||
#endif
|
BLI_assert(loc != -1);
|
||||||
write_attr_location(binding, a_idx, input->location);
|
|
||||||
|
write_attr_location(binding, a_idx, loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,8 +25,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GPU_shader_interface.h"
|
|
||||||
#include "GPU_vertex_format.h"
|
#include "GPU_vertex_format.h"
|
||||||
|
#include "gpu_shader_interface.hh"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -35,9 +35,7 @@ extern "C" {
|
|||||||
/* TODO(fclem) remove, use shaderface directly. */
|
/* TODO(fclem) remove, use shaderface directly. */
|
||||||
void AttrBinding_clear(GPUAttrBinding *binding);
|
void AttrBinding_clear(GPUAttrBinding *binding);
|
||||||
|
|
||||||
void get_attr_locations(const GPUVertFormat *format,
|
void get_attr_locations(const GPUVertFormat *format, GPUAttrBinding *binding, GPUShader *shader);
|
||||||
GPUAttrBinding *binding,
|
|
||||||
const GPUShaderInterface *shaderface);
|
|
||||||
uint read_attr_location(const GPUAttrBinding *binding, uint a_idx);
|
uint read_attr_location(const GPUAttrBinding *binding, uint a_idx);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
#include "GPU_batch.h"
|
#include "GPU_batch.h"
|
||||||
#include "GPU_context.h"
|
#include "GPU_context.h"
|
||||||
#include "GPU_shader_interface.h"
|
|
||||||
|
|
||||||
namespace blender {
|
namespace blender {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
@@ -73,7 +73,6 @@ typedef struct {
|
|||||||
GLuint vao_id;
|
GLuint vao_id;
|
||||||
|
|
||||||
GPUShader *bound_program;
|
GPUShader *bound_program;
|
||||||
const GPUShaderInterface *shader_interface;
|
|
||||||
GPUAttrBinding attr_binding;
|
GPUAttrBinding attr_binding;
|
||||||
uint16_t prev_enabled_attr_bits; /* <-- only affects this VAO, so we're ok */
|
uint16_t prev_enabled_attr_bits; /* <-- only affects this VAO, so we're ok */
|
||||||
} Immediate;
|
} Immediate;
|
||||||
@@ -148,14 +147,13 @@ void immBindShader(GPUShader *shader)
|
|||||||
BLI_assert(imm.bound_program == NULL);
|
BLI_assert(imm.bound_program == NULL);
|
||||||
|
|
||||||
imm.bound_program = shader;
|
imm.bound_program = shader;
|
||||||
imm.shader_interface = shader->interface;
|
|
||||||
|
|
||||||
if (!imm.vertex_format.packed) {
|
if (!imm.vertex_format.packed) {
|
||||||
VertexFormat_pack(&imm.vertex_format);
|
VertexFormat_pack(&imm.vertex_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU_shader_bind(shader);
|
GPU_shader_bind(shader);
|
||||||
get_attr_locations(&imm.vertex_format, &imm.attr_binding, imm.shader_interface);
|
get_attr_locations(&imm.vertex_format, &imm.attr_binding, shader);
|
||||||
GPU_matrix_bind(shader);
|
GPU_matrix_bind(shader);
|
||||||
GPU_shader_set_srgb_uniform(shader);
|
GPU_shader_set_srgb_uniform(shader);
|
||||||
}
|
}
|
||||||
|
@@ -21,8 +21,6 @@
|
|||||||
* \ingroup gpu
|
* \ingroup gpu
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "GPU_shader_interface.h"
|
|
||||||
|
|
||||||
#include "gpu_context_private.hh"
|
#include "gpu_context_private.hh"
|
||||||
#include "gpu_matrix_private.h"
|
#include "gpu_matrix_private.h"
|
||||||
|
|
||||||
|
@@ -196,8 +196,8 @@ Shader::Shader(const char *sh_name)
|
|||||||
|
|
||||||
Shader::~Shader()
|
Shader::~Shader()
|
||||||
{
|
{
|
||||||
if (this->interface) {
|
if (interface) {
|
||||||
GPU_shaderinterface_discard(this->interface);
|
delete interface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,43 +484,49 @@ void GPU_shader_transform_feedback_disable(GPUShader *shader)
|
|||||||
|
|
||||||
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
|
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
|
||||||
{
|
{
|
||||||
const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name);
|
ShaderInterface *interface = static_cast<Shader *>(shader)->interface;
|
||||||
|
const ShaderInput *uniform = interface->uniform_get(name);
|
||||||
return uniform ? uniform->location : -1;
|
return uniform ? uniform->location : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
|
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
|
||||||
{
|
{
|
||||||
return GPU_shaderinterface_uniform_builtin(shader->interface,
|
ShaderInterface *interface = static_cast<Shader *>(shader)->interface;
|
||||||
static_cast<GPUUniformBuiltin>(builtin));
|
return interface->uniform_builtin((GPUUniformBuiltin)builtin);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
|
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
|
||||||
{
|
{
|
||||||
return GPU_shaderinterface_block_builtin(shader->interface,
|
ShaderInterface *interface = static_cast<Shader *>(shader)->interface;
|
||||||
static_cast<GPUUniformBlockBuiltin>(builtin));
|
return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* DEPRECATED. */
|
||||||
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
|
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
|
||||||
{
|
{
|
||||||
const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
|
ShaderInterface *interface = static_cast<Shader *>(shader)->interface;
|
||||||
|
const ShaderInput *ubo = interface->ubo_get(name);
|
||||||
return ubo ? ubo->location : -1;
|
return ubo ? ubo->location : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name)
|
int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name)
|
||||||
{
|
{
|
||||||
const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
|
ShaderInterface *interface = static_cast<Shader *>(shader)->interface;
|
||||||
|
const ShaderInput *ubo = interface->ubo_get(name);
|
||||||
return ubo ? ubo->binding : -1;
|
return ubo ? ubo->binding : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
|
int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
|
||||||
{
|
{
|
||||||
const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name);
|
ShaderInterface *interface = static_cast<Shader *>(shader)->interface;
|
||||||
|
const ShaderInput *tex = interface->uniform_get(name);
|
||||||
return tex ? tex->binding : -1;
|
return tex ? tex->binding : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
|
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
|
||||||
{
|
{
|
||||||
const GPUShaderInput *attr = GPU_shaderinterface_attr(shader->interface, name);
|
ShaderInterface *interface = static_cast<Shader *>(shader)->interface;
|
||||||
|
const ShaderInput *attr = interface->attr_get(name);
|
||||||
return attr ? attr->location : -1;
|
return attr ? attr->location : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,161 +23,41 @@
|
|||||||
* GPU shader interface (C --> GLSL)
|
* GPU shader interface (C --> GLSL)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BKE_global.h"
|
|
||||||
|
|
||||||
#include "BLI_bitmap.h"
|
|
||||||
#include "BLI_math_base.h"
|
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
#include "GPU_shader_interface.h"
|
#include "BLI_span.hh"
|
||||||
|
#include "BLI_vector.hh"
|
||||||
|
|
||||||
#include "gpu_batch_private.hh"
|
#include "gpu_shader_interface.hh"
|
||||||
#include "gpu_context_private.hh"
|
|
||||||
|
|
||||||
#include "gl_batch.hh"
|
namespace blender::gpu {
|
||||||
|
|
||||||
#include <stddef.h>
|
ShaderInterface::ShaderInterface(void)
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define DEBUG_SHADER_INTERFACE 0
|
|
||||||
|
|
||||||
#if DEBUG_SHADER_INTERFACE
|
|
||||||
# include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace blender::gpu;
|
|
||||||
|
|
||||||
static const char *BuiltinUniform_name(GPUUniformBuiltin u)
|
|
||||||
{
|
{
|
||||||
switch (u) {
|
/* TODO(fclem) add unique ID for debugging. */
|
||||||
case GPU_UNIFORM_MODEL:
|
|
||||||
return "ModelMatrix";
|
|
||||||
case GPU_UNIFORM_VIEW:
|
|
||||||
return "ViewMatrix";
|
|
||||||
case GPU_UNIFORM_MODELVIEW:
|
|
||||||
return "ModelViewMatrix";
|
|
||||||
case GPU_UNIFORM_PROJECTION:
|
|
||||||
return "ProjectionMatrix";
|
|
||||||
case GPU_UNIFORM_VIEWPROJECTION:
|
|
||||||
return "ViewProjectionMatrix";
|
|
||||||
case GPU_UNIFORM_MVP:
|
|
||||||
return "ModelViewProjectionMatrix";
|
|
||||||
|
|
||||||
case GPU_UNIFORM_MODEL_INV:
|
|
||||||
return "ModelMatrixInverse";
|
|
||||||
case GPU_UNIFORM_VIEW_INV:
|
|
||||||
return "ViewMatrixInverse";
|
|
||||||
case GPU_UNIFORM_MODELVIEW_INV:
|
|
||||||
return "ModelViewMatrixInverse";
|
|
||||||
case GPU_UNIFORM_PROJECTION_INV:
|
|
||||||
return "ProjectionMatrixInverse";
|
|
||||||
case GPU_UNIFORM_VIEWPROJECTION_INV:
|
|
||||||
return "ViewProjectionMatrixInverse";
|
|
||||||
|
|
||||||
case GPU_UNIFORM_NORMAL:
|
|
||||||
return "NormalMatrix";
|
|
||||||
case GPU_UNIFORM_ORCO:
|
|
||||||
return "OrcoTexCoFactors";
|
|
||||||
case GPU_UNIFORM_CLIPPLANES:
|
|
||||||
return "WorldClipPlanes";
|
|
||||||
|
|
||||||
case GPU_UNIFORM_COLOR:
|
|
||||||
return "color";
|
|
||||||
case GPU_UNIFORM_BASE_INSTANCE:
|
|
||||||
return "baseInstance";
|
|
||||||
case GPU_UNIFORM_RESOURCE_CHUNK:
|
|
||||||
return "resourceChunk";
|
|
||||||
case GPU_UNIFORM_RESOURCE_ID:
|
|
||||||
return "resourceId";
|
|
||||||
case GPU_UNIFORM_SRGB_TRANSFORM:
|
|
||||||
return "srgbTarget";
|
|
||||||
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *BuiltinUniformBlock_name(GPUUniformBlockBuiltin u)
|
ShaderInterface::~ShaderInterface(void)
|
||||||
{
|
{
|
||||||
switch (u) {
|
/* Free memory used by name_buffer. */
|
||||||
case GPU_UNIFORM_BLOCK_VIEW:
|
MEM_freeN(name_buffer_);
|
||||||
return "viewBlock";
|
MEM_freeN(inputs_);
|
||||||
case GPU_UNIFORM_BLOCK_MODEL:
|
|
||||||
return "modelBlock";
|
|
||||||
case GPU_UNIFORM_BLOCK_INFO:
|
|
||||||
return "infoBlock";
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU_INLINE bool match(const char *a, const char *b)
|
static void sort_input_list(MutableSpan<ShaderInput> dst)
|
||||||
{
|
{
|
||||||
return STREQ(a, b);
|
if (dst.size() == 0) {
|
||||||
}
|
return;
|
||||||
|
|
||||||
GPU_INLINE uint hash_string(const char *str)
|
|
||||||
{
|
|
||||||
uint i = 0, c;
|
|
||||||
while ((c = *str++)) {
|
|
||||||
i = i * 37 + c;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPU_INLINE uint32_t set_input_name(GPUShaderInterface *shaderface,
|
|
||||||
GPUShaderInput *input,
|
|
||||||
char *name,
|
|
||||||
uint32_t name_len)
|
|
||||||
{
|
|
||||||
/* remove "[0]" from array name */
|
|
||||||
if (name[name_len - 1] == ']') {
|
|
||||||
name[name_len - 3] = '\0';
|
|
||||||
name_len -= 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input->name_offset = (uint32_t)(name - shaderface->name_buffer);
|
Vector<ShaderInput> inputs_vec = Vector<ShaderInput>(dst.size());
|
||||||
input->name_hash = hash_string(name);
|
MutableSpan<ShaderInput> src = inputs_vec.as_mutable_span();
|
||||||
return name_len + 1; /* include NULL terminator */
|
src.copy_from(dst);
|
||||||
}
|
|
||||||
|
|
||||||
GPU_INLINE const GPUShaderInput *input_lookup(const GPUShaderInterface *shaderface,
|
/* Simple sorting by going through the array and selecting the biggest element each time. */
|
||||||
const GPUShaderInput *const inputs,
|
for (uint i = 0; i < dst.size(); i++) {
|
||||||
const uint inputs_len,
|
ShaderInput *input_src = &src[0];
|
||||||
const char *name)
|
for (uint j = 1; j < src.size(); j++) {
|
||||||
{
|
|
||||||
const uint name_hash = hash_string(name);
|
|
||||||
/* Simple linear search for now. */
|
|
||||||
for (int i = inputs_len - 1; i >= 0; i--) {
|
|
||||||
if (inputs[i].name_hash == name_hash) {
|
|
||||||
if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) {
|
|
||||||
/* Hash colision resolve. */
|
|
||||||
for (; i >= 0 && inputs[i].name_hash == name_hash; i--) {
|
|
||||||
if (match(name, shaderface->name_buffer + inputs[i].name_offset)) {
|
|
||||||
return inputs + i; /* not found */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL; /* not found */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is a bit dangerous since we could have a hash collision.
|
|
||||||
* where the asked uniform that does not exist has the same hash
|
|
||||||
* as a real uniform. */
|
|
||||||
BLI_assert(match(name, shaderface->name_buffer + inputs[i].name_offset));
|
|
||||||
return inputs + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL; /* not found */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note that this modify the src array. */
|
|
||||||
GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const uint input_len)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < input_len; i++) {
|
|
||||||
GPUShaderInput *input_src = &src[0];
|
|
||||||
for (uint j = 1; j < input_len; j++) {
|
|
||||||
if (src[j].name_hash > input_src->name_hash) {
|
if (src[j].name_hash > input_src->name_hash) {
|
||||||
input_src = &src[j];
|
input_src = &src[j];
|
||||||
}
|
}
|
||||||
@@ -187,360 +67,60 @@ GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int block_binding(int32_t program, uint32_t block_index)
|
/* Sorts all inputs inside their respective array.
|
||||||
|
* This is to allow fast hash collision detection.
|
||||||
|
* See ShaderInterface::input_lookup for more details. */
|
||||||
|
void ShaderInterface::sort_inputs(void)
|
||||||
{
|
{
|
||||||
/* For now just assign a consecutive index. In the future, we should set it in
|
sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_));
|
||||||
* the shader using layout(binding = i) and query its value. */
|
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_));
|
||||||
glUniformBlockBinding(program, block_index, block_index);
|
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_));
|
||||||
return block_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sampler_binding(int32_t program,
|
void ShaderInterface::debug_print(void)
|
||||||
uint32_t uniform_index,
|
|
||||||
int32_t uniform_location,
|
|
||||||
int *sampler_len)
|
|
||||||
{
|
{
|
||||||
/* Identify sampler uniforms and asign sampler units to them. */
|
Span<ShaderInput> attrs = Span<ShaderInput>(inputs_, attr_len_);
|
||||||
GLint type;
|
Span<ShaderInput> ubos = Span<ShaderInput>(inputs_ + attr_len_, ubo_len_);
|
||||||
glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type);
|
Span<ShaderInput> uniforms = Span<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_);
|
||||||
|
char *name_buf = name_buffer_;
|
||||||
|
const char format[] = " | %.8x : %4d : %s\n";
|
||||||
|
|
||||||
switch (type) {
|
printf(" \033[1mGPUShaderInterface : \033[0m\n");
|
||||||
case GL_SAMPLER_1D:
|
if (attrs.size() > 0) {
|
||||||
case GL_SAMPLER_2D:
|
printf("\n Attributes :\n");
|
||||||
case GL_SAMPLER_3D:
|
|
||||||
case GL_SAMPLER_CUBE:
|
|
||||||
case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */
|
|
||||||
case GL_SAMPLER_1D_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_SHADOW:
|
|
||||||
case GL_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_SAMPLER_CUBE_SHADOW:
|
|
||||||
case GL_SAMPLER_BUFFER:
|
|
||||||
case GL_INT_SAMPLER_1D:
|
|
||||||
case GL_INT_SAMPLER_2D:
|
|
||||||
case GL_INT_SAMPLER_3D:
|
|
||||||
case GL_INT_SAMPLER_CUBE:
|
|
||||||
case GL_INT_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_BUFFER:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_3D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_BUFFER: {
|
|
||||||
/* For now just assign a consecutive index. In the future, we should set it in
|
|
||||||
* the shader using layout(binding = i) and query its value. */
|
|
||||||
int binding = *sampler_len;
|
|
||||||
glUniform1i(uniform_location, binding);
|
|
||||||
(*sampler_len)++;
|
|
||||||
return binding;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
|
} // namespace blender::gpu
|
||||||
{
|
|
||||||
#ifndef NDEBUG
|
|
||||||
GLint curr_program;
|
|
||||||
glGetIntegerv(GL_CURRENT_PROGRAM, &curr_program);
|
|
||||||
BLI_assert(curr_program == program);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GLint max_attr_name_len = 0, attr_len = 0;
|
|
||||||
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_len);
|
|
||||||
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len);
|
|
||||||
|
|
||||||
GLint max_ubo_name_len = 0, ubo_len = 0;
|
|
||||||
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len);
|
|
||||||
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len);
|
|
||||||
|
|
||||||
GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0;
|
|
||||||
glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len);
|
|
||||||
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len);
|
|
||||||
uniform_len = active_uniform_len;
|
|
||||||
|
|
||||||
/* Work around driver bug with Intel HD 4600 on Windows 7/8, where
|
|
||||||
* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */
|
|
||||||
if (attr_len > 0 && max_attr_name_len == 0) {
|
|
||||||
max_attr_name_len = 256;
|
|
||||||
}
|
|
||||||
if (ubo_len > 0 && max_ubo_name_len == 0) {
|
|
||||||
max_ubo_name_len = 256;
|
|
||||||
}
|
|
||||||
if (uniform_len > 0 && max_uniform_name_len == 0) {
|
|
||||||
max_uniform_name_len = 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before
|
|
||||||
* allocating the uniform array. */
|
|
||||||
GLint max_ubo_uni_len = 0;
|
|
||||||
for (int i = 0; i < ubo_len; i++) {
|
|
||||||
GLint ubo_uni_len;
|
|
||||||
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
|
|
||||||
max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len);
|
|
||||||
uniform_len -= ubo_uni_len;
|
|
||||||
}
|
|
||||||
/* Bit set to true if uniform comes from a uniform block. */
|
|
||||||
BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__);
|
|
||||||
/* Set uniforms from block for exclusion. */
|
|
||||||
GLint *ubo_uni_ids = (GLint *)MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__);
|
|
||||||
for (int i = 0; i < ubo_len; i++) {
|
|
||||||
GLint ubo_uni_len;
|
|
||||||
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
|
|
||||||
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids);
|
|
||||||
for (int u = 0; u < ubo_uni_len; u++) {
|
|
||||||
BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MEM_freeN(ubo_uni_ids);
|
|
||||||
|
|
||||||
uint32_t name_buffer_offset = 0;
|
|
||||||
const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len +
|
|
||||||
uniform_len * max_uniform_name_len;
|
|
||||||
|
|
||||||
int input_tot_len = attr_len + ubo_len + uniform_len;
|
|
||||||
size_t interface_size = sizeof(GPUShaderInterface) + sizeof(GPUShaderInput) * input_tot_len;
|
|
||||||
|
|
||||||
GPUShaderInterface *shaderface = (GPUShaderInterface *)MEM_callocN(interface_size,
|
|
||||||
"GPUShaderInterface");
|
|
||||||
shaderface->attribute_len = attr_len;
|
|
||||||
shaderface->ubo_len = ubo_len;
|
|
||||||
shaderface->uniform_len = uniform_len;
|
|
||||||
shaderface->name_buffer = (char *)MEM_mallocN(name_buffer_len, "name_buffer");
|
|
||||||
GPUShaderInput *inputs = shaderface->inputs;
|
|
||||||
|
|
||||||
/* Temp buffer. */
|
|
||||||
int input_tmp_len = max_iii(attr_len, ubo_len, uniform_len);
|
|
||||||
GPUShaderInput *inputs_tmp = (GPUShaderInput *)MEM_mallocN(
|
|
||||||
sizeof(GPUShaderInput) * input_tmp_len, "name_buffer");
|
|
||||||
|
|
||||||
/* Attributes */
|
|
||||||
shaderface->enabled_attr_mask = 0;
|
|
||||||
for (int i = 0, idx = 0; i < attr_len; i++) {
|
|
||||||
char *name = shaderface->name_buffer + name_buffer_offset;
|
|
||||||
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
|
||||||
GLsizei name_len = 0;
|
|
||||||
GLenum type;
|
|
||||||
GLint size;
|
|
||||||
|
|
||||||
glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name);
|
|
||||||
GLint location = glGetAttribLocation(program, name);
|
|
||||||
/* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
|
|
||||||
if (location == -1) {
|
|
||||||
shaderface->attribute_len--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPUShaderInput *input = &inputs_tmp[idx++];
|
|
||||||
input->location = input->binding = location;
|
|
||||||
|
|
||||||
name_buffer_offset += set_input_name(shaderface, input, name, name_len);
|
|
||||||
shaderface->enabled_attr_mask |= (1 << input->location);
|
|
||||||
}
|
|
||||||
sort_input_list(inputs, inputs_tmp, shaderface->attribute_len);
|
|
||||||
inputs += shaderface->attribute_len;
|
|
||||||
|
|
||||||
/* Uniform Blocks */
|
|
||||||
for (int i = 0, idx = 0; i < ubo_len; i++) {
|
|
||||||
char *name = shaderface->name_buffer + name_buffer_offset;
|
|
||||||
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
|
||||||
GLsizei name_len = 0;
|
|
||||||
|
|
||||||
glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
|
|
||||||
|
|
||||||
GPUShaderInput *input = &inputs_tmp[idx++];
|
|
||||||
input->binding = input->location = block_binding(program, i);
|
|
||||||
|
|
||||||
name_buffer_offset += set_input_name(shaderface, input, name, name_len);
|
|
||||||
shaderface->enabled_ubo_mask |= (1 << input->binding);
|
|
||||||
}
|
|
||||||
sort_input_list(inputs, inputs_tmp, shaderface->ubo_len);
|
|
||||||
inputs += shaderface->ubo_len;
|
|
||||||
|
|
||||||
/* Uniforms */
|
|
||||||
for (int i = 0, idx = 0, sampler = 0; i < active_uniform_len; i++) {
|
|
||||||
if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
char *name = shaderface->name_buffer + name_buffer_offset;
|
|
||||||
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
|
||||||
GLsizei name_len = 0;
|
|
||||||
|
|
||||||
glGetActiveUniformName(program, i, remaining_buffer, &name_len, name);
|
|
||||||
|
|
||||||
GPUShaderInput *input = &inputs_tmp[idx++];
|
|
||||||
input->location = glGetUniformLocation(program, name);
|
|
||||||
input->binding = sampler_binding(program, i, input->location, &sampler);
|
|
||||||
|
|
||||||
name_buffer_offset += set_input_name(shaderface, input, name, name_len);
|
|
||||||
shaderface->enabled_tex_mask |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
|
|
||||||
}
|
|
||||||
sort_input_list(inputs, inputs_tmp, shaderface->uniform_len);
|
|
||||||
|
|
||||||
/* Builtin Uniforms */
|
|
||||||
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
|
|
||||||
GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
|
|
||||||
shaderface->builtins[u] = glGetUniformLocation(program, BuiltinUniform_name(u));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Builtin Uniforms Blocks */
|
|
||||||
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
|
|
||||||
GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
|
|
||||||
const GPUShaderInput *block = GPU_shaderinterface_ubo(shaderface, BuiltinUniformBlock_name(u));
|
|
||||||
shaderface->builtin_blocks[u] = (block != NULL) ? block->binding : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Batches ref buffer */
|
|
||||||
shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT;
|
|
||||||
shaderface->batches = (void **)MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *),
|
|
||||||
"GPUShaderInterface batches");
|
|
||||||
|
|
||||||
MEM_freeN(uniforms_from_blocks);
|
|
||||||
MEM_freeN(inputs_tmp);
|
|
||||||
|
|
||||||
/* Resize name buffer to save some memory. */
|
|
||||||
if (name_buffer_offset < name_buffer_len) {
|
|
||||||
shaderface->name_buffer = (char *)MEM_reallocN(shaderface->name_buffer, name_buffer_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG_SHADER_INTERFACE
|
|
||||||
char *name_buf = shaderface->name_buffer;
|
|
||||||
printf("--- GPUShaderInterface %p, program %d ---\n", shaderface, program);
|
|
||||||
if (shaderface->attribute_len > 0) {
|
|
||||||
printf("Attributes {\n");
|
|
||||||
for (int i = 0; i < shaderface->attribute_len; i++) {
|
|
||||||
GPUShaderInput *input = shaderface->inputs + i;
|
|
||||||
printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset);
|
|
||||||
}
|
|
||||||
printf("};\n");
|
|
||||||
}
|
|
||||||
if (shaderface->ubo_len > 0) {
|
|
||||||
printf("Uniform Buffer Objects {\n");
|
|
||||||
for (int i = 0; i < shaderface->ubo_len; i++) {
|
|
||||||
GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + i;
|
|
||||||
printf("\t(binding = %d) %s;\n", input->binding, name_buf + input->name_offset);
|
|
||||||
}
|
|
||||||
printf("};\n");
|
|
||||||
}
|
|
||||||
if (shaderface->enabled_tex_mask > 0) {
|
|
||||||
printf("Samplers {\n");
|
|
||||||
for (int i = 0; i < shaderface->uniform_len; i++) {
|
|
||||||
GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len +
|
|
||||||
shaderface->ubo_len + i;
|
|
||||||
if (input->binding != -1) {
|
|
||||||
printf("\t(location = %d, binding = %d) %s;\n",
|
|
||||||
input->location,
|
|
||||||
input->binding,
|
|
||||||
name_buf + input->name_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("};\n");
|
|
||||||
}
|
|
||||||
if (shaderface->uniform_len > 0) {
|
|
||||||
printf("Uniforms {\n");
|
|
||||||
for (int i = 0; i < shaderface->uniform_len; i++) {
|
|
||||||
GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len +
|
|
||||||
shaderface->ubo_len + i;
|
|
||||||
if (input->binding == -1) {
|
|
||||||
printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("};\n");
|
|
||||||
}
|
|
||||||
printf("--- GPUShaderInterface end ---\n\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return shaderface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPU_shaderinterface_discard(GPUShaderInterface *shaderface)
|
|
||||||
{
|
|
||||||
/* Free memory used by name_buffer. */
|
|
||||||
MEM_freeN(shaderface->name_buffer);
|
|
||||||
/* Remove this interface from all linked Batches vao cache. */
|
|
||||||
for (int i = 0; i < shaderface->batches_len; i++) {
|
|
||||||
if (shaderface->batches[i] != NULL) {
|
|
||||||
/* XXX GL specific. to be removed during refactor. */
|
|
||||||
reinterpret_cast<GLVaoCache *>(shaderface->batches[i])->remove(shaderface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MEM_freeN(shaderface->batches);
|
|
||||||
/* Free memory used by shader interface by its self. */
|
|
||||||
MEM_freeN(shaderface);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
uint ofs = 0;
|
|
||||||
return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->attribute_len, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
uint ofs = shaderface->attribute_len;
|
|
||||||
return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->ubo_len, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
uint ofs = shaderface->attribute_len + shaderface->ubo_len;
|
|
||||||
return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->uniform_len, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface,
|
|
||||||
GPUUniformBuiltin builtin)
|
|
||||||
{
|
|
||||||
BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS);
|
|
||||||
return shaderface->builtins[builtin];
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface,
|
|
||||||
GPUUniformBlockBuiltin builtin)
|
|
||||||
{
|
|
||||||
BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS);
|
|
||||||
return shaderface->builtin_blocks[builtin];
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, void *batch)
|
|
||||||
{
|
|
||||||
int i; /* find first unused slot */
|
|
||||||
for (i = 0; i < shaderface->batches_len; i++) {
|
|
||||||
if (shaderface->batches[i] == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == shaderface->batches_len) {
|
|
||||||
/* Not enough place, realloc the array. */
|
|
||||||
i = shaderface->batches_len;
|
|
||||||
shaderface->batches_len += GPU_SHADERINTERFACE_REF_ALLOC_COUNT;
|
|
||||||
shaderface->batches = (void **)MEM_recallocN(shaderface->batches,
|
|
||||||
sizeof(void *) * shaderface->batches_len);
|
|
||||||
}
|
|
||||||
/** XXX todo cleanup. */
|
|
||||||
shaderface->batches[i] = reinterpret_cast<void *>(batch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, void *batch)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < shaderface->batches_len; i++) {
|
|
||||||
if (shaderface->batches[i] == batch) {
|
|
||||||
shaderface->batches[i] = NULL;
|
|
||||||
break; /* cannot have duplicates */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
225
source/blender/gpu/intern/gpu_shader_interface.hh
Normal file
225
source/blender/gpu/intern/gpu_shader_interface.hh
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* 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) 2016 by Mike Erwin.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup gpu
|
||||||
|
*
|
||||||
|
* GPU shader interface (C --> GLSL)
|
||||||
|
*
|
||||||
|
* Structure detailling needed vertex inputs and resources for a specific shader.
|
||||||
|
* A shader interface can be shared between two similar shaders.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstring> /* required for STREQ later on. */
|
||||||
|
|
||||||
|
#include "BLI_hash.h"
|
||||||
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
|
#include "GPU_shader.h"
|
||||||
|
|
||||||
|
namespace blender::gpu {
|
||||||
|
|
||||||
|
typedef struct ShaderInput {
|
||||||
|
uint32_t name_offset;
|
||||||
|
uint32_t name_hash;
|
||||||
|
int32_t location;
|
||||||
|
/** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attribs. */
|
||||||
|
int32_t binding;
|
||||||
|
} ShaderInput;
|
||||||
|
|
||||||
|
class ShaderInterface {
|
||||||
|
/* TODO(fclem) should be protected. */
|
||||||
|
public:
|
||||||
|
/** Flat array. In this order: Attributes, Ubos, Uniforms. */
|
||||||
|
ShaderInput *inputs_ = NULL;
|
||||||
|
/** Buffer containing all inputs names separated by '\0'. */
|
||||||
|
char *name_buffer_ = NULL;
|
||||||
|
/** Input counts inside input array. */
|
||||||
|
uint attr_len_ = 0;
|
||||||
|
uint ubo_len_ = 0;
|
||||||
|
uint uniform_len_ = 0;
|
||||||
|
/** Enabled bindpoints that needs to be fed with data. */
|
||||||
|
uint16_t enabled_attr_mask_ = 0;
|
||||||
|
uint16_t enabled_ubo_mask_ = 0;
|
||||||
|
uint64_t enabled_tex_mask_ = 0;
|
||||||
|
/** Location of builtin uniforms. Fast access, no lookup needed. */
|
||||||
|
int32_t builtins_[GPU_NUM_UNIFORMS];
|
||||||
|
int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS];
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShaderInterface();
|
||||||
|
virtual ~ShaderInterface();
|
||||||
|
|
||||||
|
void debug_print(void);
|
||||||
|
|
||||||
|
inline const ShaderInput *attr_get(const char *name) const
|
||||||
|
{
|
||||||
|
return input_lookup(inputs_, attr_len_, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ShaderInput *ubo_get(const char *name) const
|
||||||
|
{
|
||||||
|
return input_lookup(inputs_ + attr_len_, ubo_len_, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ShaderInput *uniform_get(const char *name) const
|
||||||
|
{
|
||||||
|
return input_lookup(inputs_ + attr_len_ + ubo_len_, uniform_len_, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns uniform location. */
|
||||||
|
inline int32_t uniform_builtin(const GPUUniformBuiltin builtin) const
|
||||||
|
{
|
||||||
|
BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS);
|
||||||
|
return builtins_[builtin];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns binding position. */
|
||||||
|
inline int32_t ubo_builtin(const GPUUniformBlockBuiltin builtin) const
|
||||||
|
{
|
||||||
|
BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS);
|
||||||
|
return builtin_blocks_[builtin];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static inline const char *builtin_uniform_name(GPUUniformBuiltin u);
|
||||||
|
static inline const char *builtin_uniform_block_name(GPUUniformBlockBuiltin u);
|
||||||
|
|
||||||
|
inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const;
|
||||||
|
|
||||||
|
/* Finalize interface construction by sorting the ShaderInputs for faster lookups. */
|
||||||
|
void sort_inputs(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline const ShaderInput *input_lookup(const ShaderInput *const inputs,
|
||||||
|
const uint inputs_len,
|
||||||
|
const char *name) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u)
|
||||||
|
{
|
||||||
|
switch (u) {
|
||||||
|
case GPU_UNIFORM_MODEL:
|
||||||
|
return "ModelMatrix";
|
||||||
|
case GPU_UNIFORM_VIEW:
|
||||||
|
return "ViewMatrix";
|
||||||
|
case GPU_UNIFORM_MODELVIEW:
|
||||||
|
return "ModelViewMatrix";
|
||||||
|
case GPU_UNIFORM_PROJECTION:
|
||||||
|
return "ProjectionMatrix";
|
||||||
|
case GPU_UNIFORM_VIEWPROJECTION:
|
||||||
|
return "ViewProjectionMatrix";
|
||||||
|
case GPU_UNIFORM_MVP:
|
||||||
|
return "ModelViewProjectionMatrix";
|
||||||
|
|
||||||
|
case GPU_UNIFORM_MODEL_INV:
|
||||||
|
return "ModelMatrixInverse";
|
||||||
|
case GPU_UNIFORM_VIEW_INV:
|
||||||
|
return "ViewMatrixInverse";
|
||||||
|
case GPU_UNIFORM_MODELVIEW_INV:
|
||||||
|
return "ModelViewMatrixInverse";
|
||||||
|
case GPU_UNIFORM_PROJECTION_INV:
|
||||||
|
return "ProjectionMatrixInverse";
|
||||||
|
case GPU_UNIFORM_VIEWPROJECTION_INV:
|
||||||
|
return "ViewProjectionMatrixInverse";
|
||||||
|
|
||||||
|
case GPU_UNIFORM_NORMAL:
|
||||||
|
return "NormalMatrix";
|
||||||
|
case GPU_UNIFORM_ORCO:
|
||||||
|
return "OrcoTexCoFactors";
|
||||||
|
case GPU_UNIFORM_CLIPPLANES:
|
||||||
|
return "WorldClipPlanes";
|
||||||
|
|
||||||
|
case GPU_UNIFORM_COLOR:
|
||||||
|
return "color";
|
||||||
|
case GPU_UNIFORM_BASE_INSTANCE:
|
||||||
|
return "baseInstance";
|
||||||
|
case GPU_UNIFORM_RESOURCE_CHUNK:
|
||||||
|
return "resourceChunk";
|
||||||
|
case GPU_UNIFORM_RESOURCE_ID:
|
||||||
|
return "resourceId";
|
||||||
|
case GPU_UNIFORM_SRGB_TRANSFORM:
|
||||||
|
return "srgbTarget";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBuiltin u)
|
||||||
|
{
|
||||||
|
switch (u) {
|
||||||
|
case GPU_UNIFORM_BLOCK_VIEW:
|
||||||
|
return "viewBlock";
|
||||||
|
case GPU_UNIFORM_BLOCK_MODEL:
|
||||||
|
return "modelBlock";
|
||||||
|
case GPU_UNIFORM_BLOCK_INFO:
|
||||||
|
return "infoBlock";
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns string length including '\0' terminator. */
|
||||||
|
inline uint32_t ShaderInterface::set_input_name(ShaderInput *input,
|
||||||
|
char *name,
|
||||||
|
uint32_t name_len) const
|
||||||
|
{
|
||||||
|
/* remove "[0]" from array name */
|
||||||
|
if (name[name_len - 1] == ']') {
|
||||||
|
name[name_len - 3] = '\0';
|
||||||
|
name_len -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input->name_offset = (uint32_t)(name - name_buffer_);
|
||||||
|
input->name_hash = BLI_hash_string(name);
|
||||||
|
return name_len + 1; /* include NULL terminator */
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs,
|
||||||
|
const uint inputs_len,
|
||||||
|
const char *name) const
|
||||||
|
{
|
||||||
|
const uint name_hash = BLI_hash_string(name);
|
||||||
|
/* Simple linear search for now. */
|
||||||
|
for (int i = inputs_len - 1; i >= 0; i--) {
|
||||||
|
if (inputs[i].name_hash == name_hash) {
|
||||||
|
if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) {
|
||||||
|
/* Hash colision resolve. */
|
||||||
|
for (; i >= 0 && inputs[i].name_hash == name_hash; i--) {
|
||||||
|
if (STREQ(name, name_buffer_ + inputs[i].name_offset)) {
|
||||||
|
return inputs + i; /* not found */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a bit dangerous since we could have a hash collision.
|
||||||
|
* where the asked uniform that does not exist has the same hash
|
||||||
|
* as a real uniform. */
|
||||||
|
BLI_assert(STREQ(name, name_buffer_ + inputs[i].name_offset));
|
||||||
|
return inputs + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender::gpu
|
@@ -23,13 +23,17 @@
|
|||||||
#include "BLI_span.hh"
|
#include "BLI_span.hh"
|
||||||
|
|
||||||
#include "GPU_shader.h"
|
#include "GPU_shader.h"
|
||||||
#include "GPU_shader_interface.h"
|
|
||||||
#include "GPU_vertex_buffer.h"
|
#include "GPU_vertex_buffer.h"
|
||||||
|
#include "gpu_shader_interface.hh"
|
||||||
|
|
||||||
namespace blender {
|
namespace blender {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
class Shader : public GPUShader {
|
class Shader : public GPUShader {
|
||||||
|
public:
|
||||||
|
/** Uniform & attribute locations for shader. */
|
||||||
|
ShaderInterface *interface;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Shader(const char *name);
|
Shader(const char *name);
|
||||||
virtual ~Shader();
|
virtual ~Shader();
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "gpu_batch_private.hh"
|
#include "gpu_batch_private.hh"
|
||||||
#include "gpu_primitive_private.h"
|
#include "gpu_primitive_private.h"
|
||||||
|
#include "gpu_shader_private.hh"
|
||||||
|
|
||||||
#include "gl_batch.hh"
|
#include "gl_batch.hh"
|
||||||
#include "gl_context.hh"
|
#include "gl_context.hh"
|
||||||
@@ -71,7 +72,7 @@ void GLVaoCache::init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new VAO object and store it in the cache. */
|
/* Create a new VAO object and store it in the cache. */
|
||||||
void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao)
|
void GLVaoCache::insert(const GLShaderInterface *interface, GLuint vao)
|
||||||
{
|
{
|
||||||
/* Now insert the cache. */
|
/* Now insert the cache. */
|
||||||
if (!is_dynamic_vao_count) {
|
if (!is_dynamic_vao_count) {
|
||||||
@@ -90,8 +91,7 @@ void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao)
|
|||||||
/* Erase previous entries, they will be added back if drawn again. */
|
/* Erase previous entries, they will be added back if drawn again. */
|
||||||
for (int i = 0; i < GPU_VAO_STATIC_LEN; i++) {
|
for (int i = 0; i < GPU_VAO_STATIC_LEN; i++) {
|
||||||
if (static_vaos.interfaces[i] != NULL) {
|
if (static_vaos.interfaces[i] != NULL) {
|
||||||
GPU_shaderinterface_remove_batch_ref(
|
const_cast<GLShaderInterface *>(static_vaos.interfaces[i])->ref_remove(this);
|
||||||
const_cast<GPUShaderInterface *>(static_vaos.interfaces[i]), this);
|
|
||||||
context_->vao_free(static_vaos.vao_ids[i]);
|
context_->vao_free(static_vaos.vao_ids[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,8 +99,8 @@ void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao)
|
|||||||
is_dynamic_vao_count = true;
|
is_dynamic_vao_count = true;
|
||||||
/* Init dynamic arrays and let the branch below set the values. */
|
/* Init dynamic arrays and let the branch below set the values. */
|
||||||
dynamic_vaos.count = GPU_BATCH_VAO_DYN_ALLOC_COUNT;
|
dynamic_vaos.count = GPU_BATCH_VAO_DYN_ALLOC_COUNT;
|
||||||
dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_callocN(
|
dynamic_vaos.interfaces = (const GLShaderInterface **)MEM_callocN(
|
||||||
dynamic_vaos.count * sizeof(GPUShaderInterface *), "dyn vaos interfaces");
|
dynamic_vaos.count * sizeof(GLShaderInterface *), "dyn vaos interfaces");
|
||||||
dynamic_vaos.vao_ids = (GLuint *)MEM_callocN(dynamic_vaos.count * sizeof(GLuint),
|
dynamic_vaos.vao_ids = (GLuint *)MEM_callocN(dynamic_vaos.count * sizeof(GLuint),
|
||||||
"dyn vaos ids");
|
"dyn vaos ids");
|
||||||
}
|
}
|
||||||
@@ -118,8 +118,8 @@ void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao)
|
|||||||
/* Not enough place, realloc the array. */
|
/* Not enough place, realloc the array. */
|
||||||
i = dynamic_vaos.count;
|
i = dynamic_vaos.count;
|
||||||
dynamic_vaos.count += GPU_BATCH_VAO_DYN_ALLOC_COUNT;
|
dynamic_vaos.count += GPU_BATCH_VAO_DYN_ALLOC_COUNT;
|
||||||
dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_recallocN(
|
dynamic_vaos.interfaces = (const GLShaderInterface **)MEM_recallocN(
|
||||||
(void *)dynamic_vaos.interfaces, sizeof(GPUShaderInterface *) * dynamic_vaos.count);
|
(void *)dynamic_vaos.interfaces, sizeof(GLShaderInterface *) * dynamic_vaos.count);
|
||||||
dynamic_vaos.vao_ids = (GLuint *)MEM_recallocN(dynamic_vaos.vao_ids,
|
dynamic_vaos.vao_ids = (GLuint *)MEM_recallocN(dynamic_vaos.vao_ids,
|
||||||
sizeof(GLuint) * dynamic_vaos.count);
|
sizeof(GLuint) * dynamic_vaos.count);
|
||||||
}
|
}
|
||||||
@@ -127,15 +127,15 @@ void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao)
|
|||||||
dynamic_vaos.vao_ids[i] = vao;
|
dynamic_vaos.vao_ids[i] = vao;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU_shaderinterface_add_batch_ref(const_cast<GPUShaderInterface *>(interface), this);
|
const_cast<GLShaderInterface *>(interface)->ref_add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLVaoCache::remove(const GPUShaderInterface *interface)
|
void GLVaoCache::remove(const GLShaderInterface *interface)
|
||||||
{
|
{
|
||||||
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
|
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
|
||||||
GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
|
GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
|
||||||
const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
|
const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
|
||||||
static_vaos.interfaces;
|
static_vaos.interfaces;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
if (interfaces[i] == interface) {
|
if (interfaces[i] == interface) {
|
||||||
context_->vao_free(vaos[i]);
|
context_->vao_free(vaos[i]);
|
||||||
@@ -151,8 +151,8 @@ void GLVaoCache::clear(void)
|
|||||||
GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get());
|
GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get());
|
||||||
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
|
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
|
||||||
GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
|
GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids;
|
||||||
const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
|
const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
|
||||||
static_vaos.interfaces;
|
static_vaos.interfaces;
|
||||||
/* Early out, nothing to free. */
|
/* Early out, nothing to free. */
|
||||||
if (context_ == NULL) {
|
if (context_ == NULL) {
|
||||||
return;
|
return;
|
||||||
@@ -174,7 +174,7 @@ void GLVaoCache::clear(void)
|
|||||||
if (interfaces[i] == NULL) {
|
if (interfaces[i] == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
GPU_shaderinterface_remove_batch_ref(const_cast<GPUShaderInterface *>(interfaces[i]), this);
|
const_cast<GLShaderInterface *>(interfaces[i])->ref_add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_dynamic_vao_count) {
|
if (is_dynamic_vao_count) {
|
||||||
@@ -190,11 +190,11 @@ void GLVaoCache::clear(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return 0 on cache miss (invalid VAO) */
|
/* Return 0 on cache miss (invalid VAO) */
|
||||||
GLuint GLVaoCache::lookup(const GPUShaderInterface *interface)
|
GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
|
||||||
{
|
{
|
||||||
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
|
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
|
||||||
const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
|
const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces :
|
||||||
static_vaos.interfaces;
|
static_vaos.interfaces;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
if (interfaces[i] == interface) {
|
if (interfaces[i] == interface) {
|
||||||
return (is_dynamic_vao_count) ? dynamic_vaos.vao_ids[i] : static_vaos.vao_ids[i];
|
return (is_dynamic_vao_count) ? dynamic_vaos.vao_ids[i] : static_vaos.vao_ids[i];
|
||||||
@@ -226,7 +226,9 @@ GLuint GLVaoCache::base_instance_vao_get(GPUBatch *batch, int i_first)
|
|||||||
{
|
{
|
||||||
this->context_check();
|
this->context_check();
|
||||||
/* Make sure the interface is up to date. */
|
/* Make sure the interface is up to date. */
|
||||||
if (interface_ != GPU_context_active_get()->shader->interface) {
|
Shader *shader = static_cast<Shader *>(GPU_context_active_get()->shader);
|
||||||
|
GLShaderInterface *interface = static_cast<GLShaderInterface *>(shader->interface);
|
||||||
|
if (interface_ != interface) {
|
||||||
vao_get(batch);
|
vao_get(batch);
|
||||||
/* Trigger update. */
|
/* Trigger update. */
|
||||||
base_instance_ = 0;
|
base_instance_ = 0;
|
||||||
@@ -255,9 +257,10 @@ GLuint GLVaoCache::vao_get(GPUBatch *batch)
|
|||||||
{
|
{
|
||||||
this->context_check();
|
this->context_check();
|
||||||
|
|
||||||
GPUContext *ctx = GPU_context_active_get();
|
Shader *shader = static_cast<Shader *>(GPU_context_active_get()->shader);
|
||||||
if (interface_ != ctx->shader->interface) {
|
GLShaderInterface *interface = static_cast<GLShaderInterface *>(shader->interface);
|
||||||
interface_ = ctx->shader->interface;
|
if (interface_ != interface) {
|
||||||
|
interface_ = interface;
|
||||||
vao_id_ = this->lookup(interface_);
|
vao_id_ = this->lookup(interface_);
|
||||||
|
|
||||||
if (vao_id_ == 0) {
|
if (vao_id_ == 0) {
|
||||||
|
@@ -32,11 +32,11 @@
|
|||||||
|
|
||||||
#include "glew-mx.h"
|
#include "glew-mx.h"
|
||||||
|
|
||||||
#include "GPU_shader_interface.h"
|
|
||||||
|
|
||||||
namespace blender {
|
namespace blender {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
|
class GLShaderInterface;
|
||||||
|
|
||||||
#define GPU_VAO_STATIC_LEN 3
|
#define GPU_VAO_STATIC_LEN 3
|
||||||
|
|
||||||
/* Vao management: remembers all geometry state (vertex attribute bindings & element buffer)
|
/* Vao management: remembers all geometry state (vertex attribute bindings & element buffer)
|
||||||
@@ -47,7 +47,7 @@ class GLVaoCache {
|
|||||||
/** Context for which the vao_cache_ was generated. */
|
/** Context for which the vao_cache_ was generated. */
|
||||||
struct GLContext *context_ = NULL;
|
struct GLContext *context_ = NULL;
|
||||||
/** Last interface this batch was drawn with. */
|
/** Last interface this batch was drawn with. */
|
||||||
GPUShaderInterface *interface_ = NULL;
|
GLShaderInterface *interface_ = NULL;
|
||||||
/** Cached vao for the last interface. */
|
/** Cached vao for the last interface. */
|
||||||
GLuint vao_id_ = 0;
|
GLuint vao_id_ = 0;
|
||||||
/** Used whend arb_base_instance is not supported. */
|
/** Used whend arb_base_instance is not supported. */
|
||||||
@@ -58,13 +58,13 @@ class GLVaoCache {
|
|||||||
union {
|
union {
|
||||||
/** Static handle count */
|
/** Static handle count */
|
||||||
struct {
|
struct {
|
||||||
const GPUShaderInterface *interfaces[GPU_VAO_STATIC_LEN];
|
const GLShaderInterface *interfaces[GPU_VAO_STATIC_LEN];
|
||||||
GLuint vao_ids[GPU_VAO_STATIC_LEN];
|
GLuint vao_ids[GPU_VAO_STATIC_LEN];
|
||||||
} static_vaos;
|
} static_vaos;
|
||||||
/** Dynamic handle count */
|
/** Dynamic handle count */
|
||||||
struct {
|
struct {
|
||||||
uint count;
|
uint count;
|
||||||
const GPUShaderInterface **interfaces;
|
const GLShaderInterface **interfaces;
|
||||||
GLuint *vao_ids;
|
GLuint *vao_ids;
|
||||||
} dynamic_vaos;
|
} dynamic_vaos;
|
||||||
};
|
};
|
||||||
@@ -76,9 +76,9 @@ class GLVaoCache {
|
|||||||
GLuint vao_get(GPUBatch *batch);
|
GLuint vao_get(GPUBatch *batch);
|
||||||
GLuint base_instance_vao_get(GPUBatch *batch, int i_first);
|
GLuint base_instance_vao_get(GPUBatch *batch, int i_first);
|
||||||
|
|
||||||
GLuint lookup(const GPUShaderInterface *interface);
|
GLuint lookup(const GLShaderInterface *interface);
|
||||||
void insert(const GPUShaderInterface *interface, GLuint vao_id);
|
void insert(const GLShaderInterface *interface, GLuint vao_id);
|
||||||
void remove(const GPUShaderInterface *interface);
|
void remove(const GLShaderInterface *interface);
|
||||||
void clear(void);
|
void clear(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
#include "GPU_platform.h"
|
#include "GPU_platform.h"
|
||||||
|
|
||||||
#include "gl_shader.hh"
|
#include "gl_shader.hh"
|
||||||
|
#include "gl_shader_interface.hh"
|
||||||
|
|
||||||
using namespace blender;
|
using namespace blender;
|
||||||
using namespace blender::gpu;
|
using namespace blender::gpu;
|
||||||
@@ -203,10 +204,7 @@ bool GLShader::finalize(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO(fclem) We need this to modify the image binding points using glUniform.
|
interface = new GLShaderInterface(shader_program_);
|
||||||
* This could be avoided using glProgramUniform in GL 4.1. */
|
|
||||||
glUseProgram(shader_program_);
|
|
||||||
interface = GPU_shaderinterface_create(shader_program_);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
297
source/blender/gpu/opengl/gl_shader_interface.cc
Normal file
297
source/blender/gpu/opengl/gl_shader_interface.cc
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
/*
|
||||||
|
* 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) 2016 by Mike Erwin.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup gpu
|
||||||
|
*
|
||||||
|
* GPU shader interface (C --> GLSL)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BLI_bitmap.h"
|
||||||
|
|
||||||
|
#include "gl_batch.hh"
|
||||||
|
|
||||||
|
#include "gl_shader_interface.hh"
|
||||||
|
|
||||||
|
namespace blender::gpu {
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Binding assignment
|
||||||
|
*
|
||||||
|
* To mimic vulkan, we assign binding at shader creation to avoid shader recompilation.
|
||||||
|
* In the future, we should set it in the shader using layout(binding = i) and query its value.
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
static inline int block_binding(int32_t program, uint32_t block_index)
|
||||||
|
{
|
||||||
|
/* For now just assign a consecutive index. In the future, we should set it in
|
||||||
|
* the shader using layout(binding = i) and query its value. */
|
||||||
|
glUniformBlockBinding(program, block_index, block_index);
|
||||||
|
return block_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sampler_binding(int32_t program,
|
||||||
|
uint32_t uniform_index,
|
||||||
|
int32_t uniform_location,
|
||||||
|
int *sampler_len)
|
||||||
|
{
|
||||||
|
/* Identify sampler uniforms and asign sampler units to them. */
|
||||||
|
GLint type;
|
||||||
|
glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GL_SAMPLER_1D:
|
||||||
|
case GL_SAMPLER_2D:
|
||||||
|
case GL_SAMPLER_3D:
|
||||||
|
case GL_SAMPLER_CUBE:
|
||||||
|
case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */
|
||||||
|
case GL_SAMPLER_1D_SHADOW:
|
||||||
|
case GL_SAMPLER_2D_SHADOW:
|
||||||
|
case GL_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||||
|
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||||
|
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||||
|
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||||
|
case GL_SAMPLER_CUBE_SHADOW:
|
||||||
|
case GL_SAMPLER_BUFFER:
|
||||||
|
case GL_INT_SAMPLER_1D:
|
||||||
|
case GL_INT_SAMPLER_2D:
|
||||||
|
case GL_INT_SAMPLER_3D:
|
||||||
|
case GL_INT_SAMPLER_CUBE:
|
||||||
|
case GL_INT_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_INT_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
||||||
|
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||||
|
case GL_INT_SAMPLER_BUFFER:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_1D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_3D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_BUFFER: {
|
||||||
|
/* For now just assign a consecutive index. In the future, we should set it in
|
||||||
|
* the shader using layout(binding = i) and query its value. */
|
||||||
|
int binding = *sampler_len;
|
||||||
|
glUniform1i(uniform_location, binding);
|
||||||
|
(*sampler_len)++;
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Creation / Destruction
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
GLShaderInterface::GLShaderInterface(GLuint program)
|
||||||
|
{
|
||||||
|
/* Necessary to make glUniform works. */
|
||||||
|
glUseProgram(program);
|
||||||
|
|
||||||
|
GLint max_attr_name_len = 0, attr_len = 0;
|
||||||
|
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_len);
|
||||||
|
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len);
|
||||||
|
|
||||||
|
GLint max_ubo_name_len = 0, ubo_len = 0;
|
||||||
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len);
|
||||||
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len);
|
||||||
|
|
||||||
|
GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0;
|
||||||
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len);
|
||||||
|
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len);
|
||||||
|
uniform_len = active_uniform_len;
|
||||||
|
|
||||||
|
/* Work around driver bug with Intel HD 4600 on Windows 7/8, where
|
||||||
|
* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */
|
||||||
|
if (attr_len > 0 && max_attr_name_len == 0) {
|
||||||
|
max_attr_name_len = 256;
|
||||||
|
}
|
||||||
|
if (ubo_len > 0 && max_ubo_name_len == 0) {
|
||||||
|
max_ubo_name_len = 256;
|
||||||
|
}
|
||||||
|
if (uniform_len > 0 && max_uniform_name_len == 0) {
|
||||||
|
max_uniform_name_len = 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before
|
||||||
|
* allocating the uniform array. */
|
||||||
|
GLint max_ubo_uni_len = 0;
|
||||||
|
for (int i = 0; i < ubo_len; i++) {
|
||||||
|
GLint ubo_uni_len;
|
||||||
|
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
|
||||||
|
max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len);
|
||||||
|
uniform_len -= ubo_uni_len;
|
||||||
|
}
|
||||||
|
/* Bit set to true if uniform comes from a uniform block. */
|
||||||
|
BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__);
|
||||||
|
/* Set uniforms from block for exclusion. */
|
||||||
|
GLint *ubo_uni_ids = (GLint *)MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__);
|
||||||
|
for (int i = 0; i < ubo_len; i++) {
|
||||||
|
GLint ubo_uni_len;
|
||||||
|
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
|
||||||
|
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids);
|
||||||
|
for (int u = 0; u < ubo_uni_len; u++) {
|
||||||
|
BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MEM_freeN(ubo_uni_ids);
|
||||||
|
|
||||||
|
int input_tot_len = attr_len + ubo_len + uniform_len;
|
||||||
|
inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
|
||||||
|
|
||||||
|
const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len +
|
||||||
|
uniform_len * max_uniform_name_len;
|
||||||
|
name_buffer_ = (char *)MEM_mallocN(name_buffer_len, "name_buffer");
|
||||||
|
uint32_t name_buffer_offset = 0;
|
||||||
|
|
||||||
|
/* Attributes */
|
||||||
|
enabled_attr_mask_ = 0;
|
||||||
|
for (int i = 0; i < attr_len; i++) {
|
||||||
|
char *name = name_buffer_ + name_buffer_offset;
|
||||||
|
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
||||||
|
GLsizei name_len = 0;
|
||||||
|
GLenum type;
|
||||||
|
GLint size;
|
||||||
|
|
||||||
|
glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name);
|
||||||
|
GLint location = glGetAttribLocation(program, name);
|
||||||
|
/* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
|
||||||
|
if (location == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderInput *input = &inputs_[attr_len_++];
|
||||||
|
input->location = input->binding = location;
|
||||||
|
|
||||||
|
name_buffer_offset += set_input_name(input, name, name_len);
|
||||||
|
enabled_attr_mask_ |= (1 << input->location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Uniform Blocks */
|
||||||
|
for (int i = 0; i < ubo_len; i++) {
|
||||||
|
char *name = name_buffer_ + name_buffer_offset;
|
||||||
|
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
||||||
|
GLsizei name_len = 0;
|
||||||
|
|
||||||
|
glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
|
||||||
|
|
||||||
|
ShaderInput *input = &inputs_[attr_len_ + ubo_len_++];
|
||||||
|
input->binding = input->location = block_binding(program, i);
|
||||||
|
|
||||||
|
name_buffer_offset += this->set_input_name(input, name, name_len);
|
||||||
|
enabled_ubo_mask_ |= (1 << input->binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Uniforms */
|
||||||
|
for (int i = 0, sampler = 0; i < active_uniform_len; i++) {
|
||||||
|
if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char *name = name_buffer_ + name_buffer_offset;
|
||||||
|
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
||||||
|
GLsizei name_len = 0;
|
||||||
|
|
||||||
|
glGetActiveUniformName(program, i, remaining_buffer, &name_len, name);
|
||||||
|
|
||||||
|
ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_++];
|
||||||
|
input->location = glGetUniformLocation(program, name);
|
||||||
|
input->binding = sampler_binding(program, i, input->location, &sampler);
|
||||||
|
|
||||||
|
name_buffer_offset += this->set_input_name(input, name, name_len);
|
||||||
|
enabled_tex_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Builtin Uniforms Blocks */
|
||||||
|
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
|
||||||
|
GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
|
||||||
|
const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
|
||||||
|
builtin_blocks_[u] = (block != NULL) ? block->binding : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_freeN(uniforms_from_blocks);
|
||||||
|
|
||||||
|
/* Resize name buffer to save some memory. */
|
||||||
|
if (name_buffer_offset < name_buffer_len) {
|
||||||
|
name_buffer_ = (char *)MEM_reallocN(name_buffer_, name_buffer_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this->debug_print();
|
||||||
|
|
||||||
|
this->sort_inputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLShaderInterface::~GLShaderInterface()
|
||||||
|
{
|
||||||
|
for (auto *ref : refs_) {
|
||||||
|
if (ref != NULL) {
|
||||||
|
ref->remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Batch Reference
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
void GLShaderInterface::ref_add(GLVaoCache *ref)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < refs_.size(); i++) {
|
||||||
|
if (refs_[i] == NULL) {
|
||||||
|
refs_[i] = ref;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refs_.append(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLShaderInterface::ref_remove(GLVaoCache *ref)
|
||||||
|
{
|
||||||
|
for (auto *ref_iter : refs_) {
|
||||||
|
if (ref_iter == ref) {
|
||||||
|
ref_iter = NULL;
|
||||||
|
break; /* cannot have duplicates */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Validation
|
||||||
|
* TODO
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
} // namespace blender::gpu
|
60
source/blender/gpu/opengl/gl_shader_interface.hh
Normal file
60
source/blender/gpu/opengl/gl_shader_interface.hh
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* GPU shader interface (C --> GLSL)
|
||||||
|
*
|
||||||
|
* Structure detailling needed vertex inputs and resources for a specific shader.
|
||||||
|
* A shader interface can be shared between two similar shaders.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "BLI_vector.hh"
|
||||||
|
|
||||||
|
#include "glew-mx.h"
|
||||||
|
|
||||||
|
#include "gpu_shader_interface.hh"
|
||||||
|
|
||||||
|
namespace blender::gpu {
|
||||||
|
|
||||||
|
class GLVaoCache;
|
||||||
|
|
||||||
|
class GLShaderInterface : public ShaderInterface {
|
||||||
|
private:
|
||||||
|
/** Reference to VaoCaches using this interface */
|
||||||
|
Vector<GLVaoCache *> refs_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLShaderInterface(GLuint program);
|
||||||
|
~GLShaderInterface();
|
||||||
|
|
||||||
|
void ref_add(GLVaoCache *ref);
|
||||||
|
void ref_remove(GLVaoCache *ref);
|
||||||
|
|
||||||
|
// bool resource_binding_validate();
|
||||||
|
|
||||||
|
MEM_CXX_CLASS_ALLOC_FUNCS("GLShaderInterface");
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace blender::gpu
|
@@ -23,9 +23,9 @@
|
|||||||
|
|
||||||
#include "GPU_glew.h"
|
#include "GPU_glew.h"
|
||||||
|
|
||||||
#include "GPU_shader_interface.h"
|
|
||||||
#include "GPU_vertex_buffer.h"
|
#include "GPU_vertex_buffer.h"
|
||||||
|
|
||||||
|
#include "gpu_shader_interface.hh"
|
||||||
#include "gpu_vertex_format_private.h"
|
#include "gpu_vertex_format_private.h"
|
||||||
|
|
||||||
#include "gl_batch.hh"
|
#include "gl_batch.hh"
|
||||||
@@ -33,14 +33,14 @@
|
|||||||
|
|
||||||
#include "gl_vertex_array.hh"
|
#include "gl_vertex_array.hh"
|
||||||
|
|
||||||
using namespace blender::gpu;
|
namespace blender::gpu {
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name Vertex Array Bindings
|
/** \name Vertex Array Bindings
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
/* Returns enabled vertex pointers as a bitflag (one bit per attrib). */
|
/* Returns enabled vertex pointers as a bitflag (one bit per attrib). */
|
||||||
static uint16_t vbo_bind(const GPUShaderInterface *interface,
|
static uint16_t vbo_bind(const ShaderInterface *interface,
|
||||||
const GPUVertFormat *format,
|
const GPUVertFormat *format,
|
||||||
uint v_first,
|
uint v_first,
|
||||||
uint v_len,
|
uint v_len,
|
||||||
@@ -68,7 +68,7 @@ static uint16_t vbo_bind(const GPUShaderInterface *interface,
|
|||||||
|
|
||||||
for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
|
for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
|
||||||
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
|
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
|
||||||
const GPUShaderInput *input = GPU_shaderinterface_attr(interface, name);
|
const ShaderInput *input = interface->attr_get(name);
|
||||||
|
|
||||||
if (input == NULL) {
|
if (input == NULL) {
|
||||||
continue;
|
continue;
|
||||||
@@ -111,10 +111,10 @@ static uint16_t vbo_bind(const GPUShaderInterface *interface,
|
|||||||
/* Update the Attrib Binding of the currently bound VAO. */
|
/* Update the Attrib Binding of the currently bound VAO. */
|
||||||
void GLVertArray::update_bindings(const GLuint vao,
|
void GLVertArray::update_bindings(const GLuint vao,
|
||||||
const GPUBatch *batch,
|
const GPUBatch *batch,
|
||||||
const GPUShaderInterface *interface,
|
const ShaderInterface *interface,
|
||||||
const int base_instance)
|
const int base_instance)
|
||||||
{
|
{
|
||||||
uint16_t attr_mask = interface->enabled_attr_mask;
|
uint16_t attr_mask = interface->enabled_attr_mask_;
|
||||||
|
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
@@ -156,3 +156,5 @@ void GLVertArray::update_bindings(const GLuint vao,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
} // namespace blender::gpu
|
@@ -26,7 +26,7 @@
|
|||||||
#include "glew-mx.h"
|
#include "glew-mx.h"
|
||||||
|
|
||||||
#include "GPU_batch.h"
|
#include "GPU_batch.h"
|
||||||
#include "GPU_shader_interface.h"
|
#include "gl_shader_interface.hh"
|
||||||
|
|
||||||
namespace blender {
|
namespace blender {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
@@ -35,7 +35,7 @@ namespace GLVertArray {
|
|||||||
|
|
||||||
void update_bindings(const GLuint vao,
|
void update_bindings(const GLuint vao,
|
||||||
const GPUBatch *batch,
|
const GPUBatch *batch,
|
||||||
const GPUShaderInterface *interface,
|
const ShaderInterface *interface,
|
||||||
const int base_instance);
|
const int base_instance);
|
||||||
|
|
||||||
} // namespace GLVertArray
|
} // namespace GLVertArray
|
||||||
|
Reference in New Issue
Block a user