GPUShader: GL backend isolation
This commit is contained in:
		@@ -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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@
 | 
			
		||||
 | 
			
		||||
#include "GPU_batch.h"
 | 
			
		||||
#include "GPU_batch_utils.h" /* own include */
 | 
			
		||||
#include "gpu_shader_private.h"
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------------------------- */
 | 
			
		||||
/** \name Polygon Creation (2D)
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
							
								
								
									
										61
									
								
								source/blender/gpu/intern/gpu_shader_private.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								source/blender/gpu/intern/gpu_shader_private.hh
									
									
									
									
									
										Normal 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);
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										302
									
								
								source/blender/gpu/opengl/gl_shader.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								source/blender/gpu/opengl/gl_shader.cc
									
									
									
									
									
										Normal 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** \} */
 | 
			
		||||
							
								
								
									
										79
									
								
								source/blender/gpu/opengl/gl_shader.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								source/blender/gpu/opengl/gl_shader.hh
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user