OpenGL: split off framebuffer, shader and texture code into separate files.
This commit is contained in:
@@ -74,8 +74,8 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
|
||||
#include "BLI_sys_types.h" /* for intptr_t support */
|
||||
|
||||
#include "GPU_buffers.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# include "DNA_userdef_types.h"
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
|
||||
#include "GPU_buffers.h"
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
#include "BLI_sys_types.h" // for intptr_t support
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
@@ -74,9 +74,9 @@
|
||||
#endif
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_buffers.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "CCGSubSurf.h"
|
||||
|
||||
|
||||
@@ -69,9 +69,9 @@
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_compositing.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
|
||||
|
||||
#include "render_intern.h"
|
||||
|
||||
@@ -60,10 +60,10 @@
|
||||
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_basic_shader.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "RE_engine.h"
|
||||
|
||||
|
||||
@@ -87,9 +87,9 @@
|
||||
#include "BIF_glutil.h"
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_select.h"
|
||||
#include "GPU_basic_shader.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_particle.h"
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
|
||||
#include "BIF_gl.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "view3d_intern.h" // own include
|
||||
|
||||
|
||||
@@ -54,9 +54,9 @@
|
||||
#include "ED_space_api.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_compositing.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_material.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
|
||||
|
||||
@@ -96,8 +96,8 @@
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_compositing.h"
|
||||
|
||||
#include "view3d_intern.h" /* own include */
|
||||
|
||||
@@ -46,16 +46,19 @@ set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
intern/gpu_basic_shader.c
|
||||
intern/gpu_buffers.c
|
||||
intern/gpu_codegen.c
|
||||
intern/gpu_draw.c
|
||||
intern/gpu_extensions.c
|
||||
intern/gpu_init_exit.c
|
||||
intern/gpu_material.c
|
||||
intern/gpu_basic_shader.c
|
||||
intern/gpu_select.c
|
||||
intern/gpu_compositing.c
|
||||
intern/gpu_debug.c
|
||||
intern/gpu_draw.c
|
||||
intern/gpu_extensions.c
|
||||
intern/gpu_framebuffer.c
|
||||
intern/gpu_init_exit.c
|
||||
intern/gpu_material.c
|
||||
intern/gpu_select.c
|
||||
intern/gpu_shader.c
|
||||
intern/gpu_texture.c
|
||||
|
||||
shaders/gpu_program_smoke_frag.glsl
|
||||
shaders/gpu_program_smoke_color_frag.glsl
|
||||
@@ -78,16 +81,19 @@ set(SRC
|
||||
shaders/gpu_shader_vsm_store_vert.glsl
|
||||
shaders/gpu_shader_fx_depth_resolve.glsl
|
||||
|
||||
GPU_basic_shader.h
|
||||
GPU_buffers.h
|
||||
GPU_draw.h
|
||||
GPU_compositing.h
|
||||
GPU_debug.h
|
||||
GPU_draw.h
|
||||
GPU_extensions.h
|
||||
GPU_framebuffer.h
|
||||
GPU_glew.h
|
||||
GPU_init_exit.h
|
||||
GPU_material.h
|
||||
GPU_basic_shader.h
|
||||
GPU_select.h
|
||||
GPU_compositing.h
|
||||
GPU_shader.h
|
||||
GPU_texture.h
|
||||
intern/gpu_codegen.h
|
||||
intern/gpu_private.h
|
||||
)
|
||||
|
||||
@@ -129,7 +129,7 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap);
|
||||
/* Image updates and free
|
||||
* - these deal with images bound as opengl textures */
|
||||
|
||||
void GPU_paint_update_image(struct Image *ima, ImageUser *iuser, int x, int y, int w, int h);
|
||||
void GPU_paint_update_image(struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
|
||||
void GPU_update_images_framechange(void);
|
||||
int GPU_update_image_time(struct Image *ima, double time);
|
||||
int GPU_verify_image(struct Image *ima, struct ImageUser *iuser, int tftile, bool compare, bool mipmap, bool is_data);
|
||||
|
||||
@@ -36,25 +36,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Image;
|
||||
struct ImageUser;
|
||||
struct PreviewImage;
|
||||
|
||||
struct GPUTexture;
|
||||
typedef struct GPUTexture GPUTexture;
|
||||
|
||||
struct GPUFrameBuffer;
|
||||
typedef struct GPUFrameBuffer GPUFrameBuffer;
|
||||
|
||||
struct GPUOffScreen;
|
||||
typedef struct GPUOffScreen GPUOffScreen;
|
||||
|
||||
struct GPUShader;
|
||||
typedef struct GPUShader GPUShader;
|
||||
|
||||
struct GPUProgram;
|
||||
typedef struct GPUProgram GPUProgram;
|
||||
|
||||
/* GPU extensions support */
|
||||
|
||||
void GPU_extensions_disable(void);
|
||||
@@ -65,9 +46,12 @@ bool GPU_full_non_power_of_two_support(void);
|
||||
bool GPU_display_list_support(void);
|
||||
bool GPU_bicubic_bump_support(void);
|
||||
bool GPU_geometry_shader_support(void);
|
||||
bool GPU_geometry_shader_support_via_extension(void);
|
||||
bool GPU_instanced_drawing_support(void);
|
||||
|
||||
int GPU_max_texture_size(void);
|
||||
int GPU_max_textures(void);
|
||||
int GPU_max_color_texture_samples(void);
|
||||
int GPU_color_depth(void);
|
||||
void GPU_get_dfdy_factors(float fac[2]);
|
||||
|
||||
@@ -103,171 +87,6 @@ typedef enum GPUDriverType {
|
||||
|
||||
bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
|
||||
|
||||
/* GPU Texture
|
||||
* - always returns unsigned char RGBA textures
|
||||
* - if texture with non square dimensions is created, depending on the
|
||||
* graphics card capabilities the texture may actually be stored in a
|
||||
* larger texture with power of two dimensions.
|
||||
* - can use reference counting:
|
||||
* - reference counter after GPU_texture_create is 1
|
||||
* - GPU_texture_ref increases by one
|
||||
* - GPU_texture_free decreases by one, and frees if 0
|
||||
* - if created with from_blender, will not free the texture
|
||||
*/
|
||||
|
||||
typedef enum GPUHDRType {
|
||||
GPU_HDR_NONE = 0,
|
||||
GPU_HDR_HALF_FLOAT = 1,
|
||||
GPU_HDR_FULL_FLOAT = (1 << 1),
|
||||
} GPUHDRType;
|
||||
|
||||
GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
|
||||
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]);
|
||||
GPUTexture *GPU_texture_from_blender(struct Image *ima,
|
||||
struct ImageUser *iuser, bool is_data, double time, int mipmap);
|
||||
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
|
||||
void GPU_invalid_tex_init(void);
|
||||
void GPU_invalid_tex_bind(int mode);
|
||||
void GPU_invalid_tex_free(void);
|
||||
|
||||
void GPU_texture_free(GPUTexture *tex);
|
||||
|
||||
void GPU_texture_ref(GPUTexture *tex);
|
||||
|
||||
void GPU_texture_bind(GPUTexture *tex, int number);
|
||||
void GPU_texture_unbind(GPUTexture *tex);
|
||||
|
||||
void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter);
|
||||
|
||||
GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
|
||||
|
||||
int GPU_texture_target(const GPUTexture *tex);
|
||||
int GPU_texture_width(const GPUTexture *tex);
|
||||
int GPU_texture_height(const GPUTexture *tex);
|
||||
int GPU_texture_opengl_bindcode(const GPUTexture *tex);
|
||||
|
||||
/* GPU Framebuffer
|
||||
* - this is a wrapper for an OpenGL framebuffer object (FBO). in practice
|
||||
* multiple FBO's may be created, to get around limitations on the number
|
||||
* of attached textures and the dimension requirements.
|
||||
* - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must
|
||||
* be called before rendering to the window framebuffer again */
|
||||
|
||||
void GPU_texture_bind_as_framebuffer(GPUTexture *tex);
|
||||
|
||||
GPUFrameBuffer *GPU_framebuffer_create(void);
|
||||
int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]);
|
||||
void GPU_framebuffer_texture_detach(GPUTexture *tex);
|
||||
void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot);
|
||||
void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex);
|
||||
void GPU_framebuffer_free(GPUFrameBuffer *fb);
|
||||
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
|
||||
|
||||
void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot);
|
||||
|
||||
void GPU_framebuffer_restore(void);
|
||||
void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex);
|
||||
|
||||
/* GPU OffScreen
|
||||
* - wrapper around framebuffer and texture for simple offscreen drawing
|
||||
* - changes size if graphics card can't support it */
|
||||
|
||||
GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]);
|
||||
void GPU_offscreen_free(GPUOffScreen *ofs);
|
||||
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
|
||||
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
|
||||
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
|
||||
int GPU_offscreen_width(const GPUOffScreen *ofs);
|
||||
int GPU_offscreen_height(const GPUOffScreen *ofs);
|
||||
int GPU_offscreen_color_texture(const GPUOffScreen *ofs);
|
||||
|
||||
/* Builtin/Non-generated shaders */
|
||||
typedef enum GPUProgramType {
|
||||
GPU_PROGRAM_TYPE_FRAGMENT = 0
|
||||
} GPUProgramType;
|
||||
|
||||
/* TODO: remove ARB program support (recode smoke shader in GLSL) */
|
||||
GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code);
|
||||
void GPU_program_free(GPUProgram *program);
|
||||
void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w);
|
||||
void GPU_program_bind(GPUProgram *);
|
||||
void GPU_program_unbind(GPUProgram *);
|
||||
|
||||
/* GPU Shader
|
||||
* - only for fragment shaders now
|
||||
* - must call texture bind before setting a texture as uniform! */
|
||||
|
||||
GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number);
|
||||
enum {
|
||||
GPU_SHADER_FLAGS_NONE = 0,
|
||||
GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0),
|
||||
};
|
||||
GPUShader *GPU_shader_create_ex(const char *vertexcode,
|
||||
const char *fragcode,
|
||||
const char *geocode,
|
||||
const char *libcode,
|
||||
const char *defines,
|
||||
int input,
|
||||
int output,
|
||||
int number,
|
||||
const int flags);
|
||||
void GPU_shader_free(GPUShader *shader);
|
||||
|
||||
void GPU_shader_bind(GPUShader *shader);
|
||||
void GPU_shader_unbind(void);
|
||||
|
||||
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
|
||||
void GPU_shader_uniform_vector(GPUShader *shader, int location, int length,
|
||||
int arraysize, const float *value);
|
||||
void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length,
|
||||
int arraysize, const int *value);
|
||||
|
||||
void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex);
|
||||
void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
|
||||
void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number);
|
||||
|
||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
|
||||
|
||||
/* Builtin/Non-generated shaders */
|
||||
typedef enum GPUBuiltinShader {
|
||||
GPU_SHADER_VSM_STORE = 0,
|
||||
GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
|
||||
} GPUBuiltinShader;
|
||||
|
||||
typedef enum GPUBuiltinProgram {
|
||||
GPU_PROGRAM_SMOKE = 0,
|
||||
GPU_PROGRAM_SMOKE_COLORED = 1,
|
||||
} GPUBuiltinProgram;
|
||||
|
||||
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
|
||||
GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program);
|
||||
GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
|
||||
|
||||
void GPU_shader_free_builtin_shaders(void);
|
||||
|
||||
/* Vertex attributes for shaders */
|
||||
|
||||
#define GPU_MAX_ATTRIB 32
|
||||
|
||||
typedef struct GPUVertexAttribs {
|
||||
struct {
|
||||
int type;
|
||||
int glindex;
|
||||
int gltexco;
|
||||
int attribid;
|
||||
char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
|
||||
} layer[GPU_MAX_ATTRIB];
|
||||
|
||||
int totlayer;
|
||||
} GPUVertexAttribs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
84
source/blender/gpu/GPU_framebuffer.h
Normal file
84
source/blender/gpu/GPU_framebuffer.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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) 2005 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Brecht Van Lommel.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file GPU_framebuffer.h
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#ifndef __GPU_FRAMEBUFFER_H__
|
||||
#define __GPU_FRAMEBUFFER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct GPUFrameBuffer GPUFrameBuffer;
|
||||
typedef struct GPUOffScreen GPUOffScreen;
|
||||
typedef struct GPUTexture GPUTexture;
|
||||
|
||||
/* GPU Framebuffer
|
||||
* - this is a wrapper for an OpenGL framebuffer object (FBO). in practice
|
||||
* multiple FBO's may be created, to get around limitations on the number
|
||||
* of attached textures and the dimension requirements.
|
||||
* - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must
|
||||
* be called before rendering to the window framebuffer again */
|
||||
|
||||
void GPU_texture_bind_as_framebuffer(GPUTexture *tex);
|
||||
|
||||
GPUFrameBuffer *GPU_framebuffer_create(void);
|
||||
int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]);
|
||||
void GPU_framebuffer_texture_detach(GPUTexture *tex);
|
||||
void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot);
|
||||
void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex);
|
||||
void GPU_framebuffer_free(GPUFrameBuffer *fb);
|
||||
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
|
||||
|
||||
void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot);
|
||||
|
||||
bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
|
||||
|
||||
void GPU_framebuffer_restore(void);
|
||||
void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex);
|
||||
|
||||
/* GPU OffScreen
|
||||
* - wrapper around framebuffer and texture for simple offscreen drawing
|
||||
* - changes size if graphics card can't support it */
|
||||
|
||||
GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]);
|
||||
void GPU_offscreen_free(GPUOffScreen *ofs);
|
||||
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
|
||||
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
|
||||
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
|
||||
int GPU_offscreen_width(const GPUOffScreen *ofs);
|
||||
int GPU_offscreen_height(const GPUOffScreen *ofs);
|
||||
int GPU_offscreen_color_texture(const GPUOffScreen *ofs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GPU_FRAMEBUFFER_H__ */
|
||||
127
source/blender/gpu/GPU_shader.h
Normal file
127
source/blender/gpu/GPU_shader.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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) 2005 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Brecht Van Lommel.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file GPU_shader.h
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#ifndef __GPU_SHADER_H__
|
||||
#define __GPU_SHADER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct GPUShader GPUShader;
|
||||
typedef struct GPUProgram GPUProgram;
|
||||
typedef struct GPUTexture GPUTexture;
|
||||
|
||||
/* Builtin/Non-generated shaders */
|
||||
typedef enum GPUProgramType {
|
||||
GPU_PROGRAM_TYPE_FRAGMENT = 0
|
||||
} GPUProgramType;
|
||||
|
||||
/* TODO: remove ARB program support (recode smoke shader in GLSL) */
|
||||
GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code);
|
||||
void GPU_program_free(GPUProgram *program);
|
||||
void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w);
|
||||
void GPU_program_bind(GPUProgram *);
|
||||
void GPU_program_unbind(GPUProgram *);
|
||||
|
||||
/* GPU Shader
|
||||
* - only for fragment shaders now
|
||||
* - must call texture bind before setting a texture as uniform! */
|
||||
|
||||
GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number);
|
||||
enum {
|
||||
GPU_SHADER_FLAGS_NONE = 0,
|
||||
GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0),
|
||||
};
|
||||
GPUShader *GPU_shader_create_ex(const char *vertexcode,
|
||||
const char *fragcode,
|
||||
const char *geocode,
|
||||
const char *libcode,
|
||||
const char *defines,
|
||||
int input,
|
||||
int output,
|
||||
int number,
|
||||
const int flags);
|
||||
void GPU_shader_free(GPUShader *shader);
|
||||
|
||||
void GPU_shader_bind(GPUShader *shader);
|
||||
void GPU_shader_unbind(void);
|
||||
|
||||
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
|
||||
void GPU_shader_uniform_vector(GPUShader *shader, int location, int length,
|
||||
int arraysize, const float *value);
|
||||
void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length,
|
||||
int arraysize, const int *value);
|
||||
|
||||
void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex);
|
||||
void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
|
||||
void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number);
|
||||
|
||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
|
||||
|
||||
/* Builtin/Non-generated shaders */
|
||||
typedef enum GPUBuiltinShader {
|
||||
GPU_SHADER_VSM_STORE = 0,
|
||||
GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
|
||||
} GPUBuiltinShader;
|
||||
|
||||
typedef enum GPUBuiltinProgram {
|
||||
GPU_PROGRAM_SMOKE = 0,
|
||||
GPU_PROGRAM_SMOKE_COLORED = 1,
|
||||
} GPUBuiltinProgram;
|
||||
|
||||
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
|
||||
GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program);
|
||||
GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
|
||||
|
||||
void GPU_shader_free_builtin_shaders(void);
|
||||
|
||||
/* Vertex attributes for shaders */
|
||||
|
||||
#define GPU_MAX_ATTRIB 32
|
||||
|
||||
typedef struct GPUVertexAttribs {
|
||||
struct {
|
||||
int type;
|
||||
int glindex;
|
||||
int gltexco;
|
||||
int attribid;
|
||||
char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
|
||||
} layer[GPU_MAX_ATTRIB];
|
||||
|
||||
int totlayer;
|
||||
} GPUVertexAttribs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GPU_SHADER_H__ */
|
||||
104
source/blender/gpu/GPU_texture.h
Normal file
104
source/blender/gpu/GPU_texture.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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) 2005 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Brecht Van Lommel.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file GPU_texture.h
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#ifndef __GPU_TEXTURE_H__
|
||||
#define __GPU_TEXTURE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Image;
|
||||
struct ImageUser;
|
||||
struct PreviewImage;
|
||||
|
||||
typedef struct GPUFrameBuffer GPUFrameBuffer;
|
||||
typedef struct GPUTexture GPUTexture;
|
||||
|
||||
/* GPU Texture
|
||||
* - always returns unsigned char RGBA textures
|
||||
* - if texture with non square dimensions is created, depending on the
|
||||
* graphics card capabilities the texture may actually be stored in a
|
||||
* larger texture with power of two dimensions.
|
||||
* - can use reference counting:
|
||||
* - reference counter after GPU_texture_create is 1
|
||||
* - GPU_texture_ref increases by one
|
||||
* - GPU_texture_free decreases by one, and frees if 0
|
||||
* - if created with from_blender, will not free the texture
|
||||
*/
|
||||
|
||||
typedef enum GPUHDRType {
|
||||
GPU_HDR_NONE = 0,
|
||||
GPU_HDR_HALF_FLOAT = 1,
|
||||
GPU_HDR_FULL_FLOAT = (1 << 1),
|
||||
} GPUHDRType;
|
||||
|
||||
GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
|
||||
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]);
|
||||
GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]);
|
||||
GPUTexture *GPU_texture_from_blender(struct Image *ima,
|
||||
struct ImageUser *iuser, bool is_data, double time, int mipmap);
|
||||
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
|
||||
void GPU_invalid_tex_init(void);
|
||||
void GPU_invalid_tex_bind(int mode);
|
||||
void GPU_invalid_tex_free(void);
|
||||
|
||||
void GPU_texture_free(GPUTexture *tex);
|
||||
|
||||
void GPU_texture_ref(GPUTexture *tex);
|
||||
|
||||
void GPU_texture_bind(GPUTexture *tex, int number);
|
||||
void GPU_texture_unbind(GPUTexture *tex);
|
||||
int GPU_texture_bound_number(GPUTexture *tex);
|
||||
|
||||
void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter);
|
||||
|
||||
GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
|
||||
int GPU_texture_framebuffer_attachment(GPUTexture *tex);
|
||||
void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment);
|
||||
|
||||
int GPU_texture_target(const GPUTexture *tex);
|
||||
int GPU_texture_width(const GPUTexture *tex);
|
||||
int GPU_texture_height(const GPUTexture *tex);
|
||||
int GPU_texture_depth(const GPUTexture *tex);
|
||||
int GPU_texture_opengl_bindcode(const GPUTexture *tex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GPU_TEXTURE_H__ */
|
||||
@@ -42,13 +42,12 @@
|
||||
* - Optimize for case where no texture matrix is used.
|
||||
*/
|
||||
|
||||
#include "GPU_glew.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_basic_shader.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
/* State */
|
||||
|
||||
|
||||
@@ -42,9 +42,11 @@
|
||||
#include "BLI_dynstr.h"
|
||||
#include "BLI_ghash.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "BLI_sys_types.h" /* for intptr_t support */
|
||||
|
||||
|
||||
@@ -47,10 +47,12 @@
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_gpu_types.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_compositing.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
|
||||
@@ -75,11 +75,13 @@
|
||||
#include "BKE_subsurf.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
|
||||
#include "GPU_basic_shader.h"
|
||||
#include "GPU_buffers.h"
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_basic_shader.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
633
source/blender/gpu/intern/gpu_framebuffer.c
Normal file
633
source/blender/gpu/intern/gpu_framebuffer.c
Normal file
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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) 2005 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Brecht Van Lommel.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "GPU_debug.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
static struct GPUFrameBufferGlobal {
|
||||
GLuint currentfb;
|
||||
} GG = {0};
|
||||
|
||||
/* Number of maximum output slots. We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */
|
||||
#define GPU_FB_MAX_SLOTS 4
|
||||
|
||||
struct GPUFrameBuffer {
|
||||
GLuint object;
|
||||
GPUTexture *colortex[GPU_FB_MAX_SLOTS];
|
||||
GPUTexture *depthtex;
|
||||
};
|
||||
|
||||
static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
|
||||
{
|
||||
const char *err = "unknown";
|
||||
|
||||
switch (status) {
|
||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||
break;
|
||||
case GL_INVALID_OPERATION:
|
||||
err = "Invalid operation";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
||||
err = "Incomplete attachment";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
||||
err = "Unsupported framebuffer format";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
|
||||
err = "Missing attachment";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
|
||||
err = "Attached images must have same dimensions";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
|
||||
err = "Attached images must have same format";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
|
||||
err = "Missing draw buffer";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
||||
err = "Missing read buffer";
|
||||
break;
|
||||
}
|
||||
|
||||
if (err_out) {
|
||||
BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
|
||||
(int)status, err);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
|
||||
(int)status, err);
|
||||
}
|
||||
}
|
||||
|
||||
/* GPUFrameBuffer */
|
||||
|
||||
GPUFrameBuffer *GPU_framebuffer_create(void)
|
||||
{
|
||||
GPUFrameBuffer *fb;
|
||||
|
||||
if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object || (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit)))
|
||||
return NULL;
|
||||
|
||||
fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
|
||||
glGenFramebuffersEXT(1, &fb->object);
|
||||
|
||||
if (!fb->object) {
|
||||
fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
|
||||
(int)glGetError());
|
||||
GPU_framebuffer_free(fb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
|
||||
glReadBuffer(GL_NONE);
|
||||
glDrawBuffer(GL_NONE);
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256])
|
||||
{
|
||||
GLenum attachment;
|
||||
GLenum error;
|
||||
|
||||
if (slot >= GPU_FB_MAX_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"Attaching to index %d framebuffer slot unsupported. "
|
||||
"Use at most %d\n", slot, GPU_FB_MAX_SLOTS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((G.debug & G_DEBUG)) {
|
||||
if (GPU_texture_bound_number(tex) != -1) {
|
||||
fprintf(stderr,
|
||||
"Feedback loop warning!: "
|
||||
"Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (GPU_texture_depth(tex))
|
||||
attachment = GL_DEPTH_ATTACHMENT_EXT;
|
||||
else
|
||||
attachment = GL_COLOR_ATTACHMENT0_EXT + slot;
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
|
||||
GG.currentfb = fb->object;
|
||||
|
||||
/* Clean glError buffer. */
|
||||
while (glGetError() != GL_NO_ERROR) {}
|
||||
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
|
||||
GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0);
|
||||
|
||||
error = glGetError();
|
||||
|
||||
if (error == GL_INVALID_OPERATION) {
|
||||
GPU_framebuffer_restore();
|
||||
GPU_print_framebuffer_error(error, err_out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (GPU_texture_depth(tex))
|
||||
fb->depthtex = tex;
|
||||
else
|
||||
fb->colortex[slot] = tex;
|
||||
|
||||
GPU_texture_framebuffer_set(tex, fb, slot);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GPU_framebuffer_texture_detach(GPUTexture *tex)
|
||||
{
|
||||
GLenum attachment;
|
||||
GPUFrameBuffer *fb = GPU_texture_framebuffer(tex);
|
||||
int fb_attachment = GPU_texture_framebuffer_attachment(tex);
|
||||
|
||||
if (!fb)
|
||||
return;
|
||||
|
||||
if (GG.currentfb != fb->object) {
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
|
||||
GG.currentfb = fb->object;
|
||||
}
|
||||
|
||||
if (GPU_texture_depth(tex)) {
|
||||
fb->depthtex = NULL;
|
||||
attachment = GL_DEPTH_ATTACHMENT_EXT;
|
||||
}
|
||||
else {
|
||||
BLI_assert(fb->colortex[fb_attachment] == tex);
|
||||
fb->colortex[fb_attachment] = NULL;
|
||||
attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment;
|
||||
}
|
||||
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0);
|
||||
|
||||
GPU_texture_framebuffer_set(tex, NULL, -1);
|
||||
}
|
||||
|
||||
void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
|
||||
{
|
||||
GPUFrameBuffer *fb = GPU_texture_framebuffer(tex);
|
||||
int fb_attachment = GPU_texture_framebuffer_attachment(tex);
|
||||
|
||||
if (!fb) {
|
||||
fprintf(stderr, "Error, texture not bound to framebuffer!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* push attributes */
|
||||
glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
/* bind framebuffer */
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
|
||||
|
||||
if (GPU_texture_depth(tex)) {
|
||||
glDrawBuffer(GL_NONE);
|
||||
glReadBuffer(GL_NONE);
|
||||
}
|
||||
else {
|
||||
/* last bound prevails here, better allow explicit control here too */
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment);
|
||||
}
|
||||
|
||||
if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) {
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
}
|
||||
|
||||
/* push matrices and set default viewport and matrix */
|
||||
glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
|
||||
GG.currentfb = fb->object;
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
}
|
||||
|
||||
void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
|
||||
{
|
||||
int numslots = 0, i;
|
||||
GLenum attachments[4];
|
||||
|
||||
if (!fb->colortex[slot]) {
|
||||
fprintf(stderr, "Error, framebuffer slot empty!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (fb->colortex[i]) {
|
||||
attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
|
||||
numslots++;
|
||||
}
|
||||
}
|
||||
|
||||
/* push attributes */
|
||||
glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
/* bind framebuffer */
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
|
||||
|
||||
/* last bound prevails here, better allow explicit control here too */
|
||||
glDrawBuffers(numslots, attachments);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
|
||||
|
||||
/* push matrices and set default viewport and matrix */
|
||||
glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
|
||||
GG.currentfb = fb->object;
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
}
|
||||
|
||||
|
||||
void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
|
||||
{
|
||||
/* restore matrix */
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
|
||||
/* restore attributes */
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
|
||||
/* last bound prevails here, better allow explicit control here too */
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
|
||||
|
||||
/* push matrices and set default viewport and matrix */
|
||||
glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
|
||||
GG.currentfb = fb->object;
|
||||
GG.currentfb = fb->object;
|
||||
}
|
||||
|
||||
bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
|
||||
{
|
||||
return fb->object == GG.currentfb;
|
||||
}
|
||||
|
||||
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
|
||||
{
|
||||
GLenum status;
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
|
||||
GG.currentfb = fb->object;
|
||||
|
||||
/* Clean glError buffer. */
|
||||
while (glGetError() != GL_NO_ERROR) {}
|
||||
|
||||
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
|
||||
GPU_framebuffer_restore();
|
||||
GPU_print_framebuffer_error(status, err_out);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPU_framebuffer_free(GPUFrameBuffer *fb)
|
||||
{
|
||||
int i;
|
||||
if (fb->depthtex)
|
||||
GPU_framebuffer_texture_detach(fb->depthtex);
|
||||
|
||||
for (i = 0; i < GPU_FB_MAX_SLOTS; i++) {
|
||||
if (fb->colortex[i]) {
|
||||
GPU_framebuffer_texture_detach(fb->colortex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (fb->object) {
|
||||
glDeleteFramebuffersEXT(1, &fb->object);
|
||||
|
||||
if (GG.currentfb == fb->object) {
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
GG.currentfb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(fb);
|
||||
}
|
||||
|
||||
void GPU_framebuffer_restore(void)
|
||||
{
|
||||
if (GG.currentfb != 0) {
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
GG.currentfb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex)
|
||||
{
|
||||
const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f};
|
||||
const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)};
|
||||
|
||||
GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
|
||||
int scale_uniform, texture_source_uniform;
|
||||
|
||||
if (!blur_shader)
|
||||
return;
|
||||
|
||||
scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU");
|
||||
texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource");
|
||||
|
||||
/* Blurring horizontally */
|
||||
|
||||
/* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid
|
||||
* pushing unnecessary matrices onto the OpenGL stack. */
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
|
||||
/* avoid warnings from texture binding */
|
||||
GG.currentfb = blurfb->object;
|
||||
|
||||
GPU_shader_bind(blur_shader);
|
||||
GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh);
|
||||
GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
|
||||
glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex));
|
||||
|
||||
/* Peparing to draw quad */
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
GPU_texture_bind(tex, 0);
|
||||
|
||||
/* Drawing quad */
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2d(0, 0); glVertex2f(1, 1);
|
||||
glTexCoord2d(1, 0); glVertex2f(-1, 1);
|
||||
glTexCoord2d(1, 1); glVertex2f(-1, -1);
|
||||
glTexCoord2d(0, 1); glVertex2f(1, -1);
|
||||
glEnd();
|
||||
|
||||
/* Blurring vertically */
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
|
||||
GG.currentfb = fb->object;
|
||||
|
||||
glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
|
||||
GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev);
|
||||
GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex);
|
||||
GPU_texture_bind(blurtex, 0);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2d(0, 0); glVertex2f(1, 1);
|
||||
glTexCoord2d(1, 0); glVertex2f(-1, 1);
|
||||
glTexCoord2d(1, 1); glVertex2f(-1, -1);
|
||||
glTexCoord2d(0, 1); glVertex2f(1, -1);
|
||||
glEnd();
|
||||
|
||||
GPU_shader_unbind();
|
||||
}
|
||||
|
||||
/* GPUOffScreen */
|
||||
|
||||
struct GPUOffScreen {
|
||||
GPUFrameBuffer *fb;
|
||||
GPUTexture *color;
|
||||
GPUTexture *depth;
|
||||
};
|
||||
|
||||
GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256])
|
||||
{
|
||||
GPUOffScreen *ofs;
|
||||
|
||||
ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
|
||||
|
||||
ofs->fb = GPU_framebuffer_create();
|
||||
if (!ofs->fb) {
|
||||
GPU_offscreen_free(ofs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (samples) {
|
||||
if (!GLEW_EXT_framebuffer_multisample ||
|
||||
!GLEW_ARB_texture_multisample ||
|
||||
/* Only needed for GPU_offscreen_read_pixels.
|
||||
* We could add an arg if we intend to use multi-sample
|
||||
* offscreen buffers w/o reading their pixels */
|
||||
!GLEW_EXT_framebuffer_blit ||
|
||||
/* This is required when blitting from a multi-sampled buffers,
|
||||
* even though we're not scaling. */
|
||||
!GLEW_EXT_framebuffer_multisample_blit_scaled)
|
||||
{
|
||||
samples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out);
|
||||
if (!ofs->depth) {
|
||||
GPU_offscreen_free(ofs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) {
|
||||
GPU_offscreen_free(ofs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out);
|
||||
if (!ofs->color) {
|
||||
GPU_offscreen_free(ofs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) {
|
||||
GPU_offscreen_free(ofs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check validity at the very end! */
|
||||
if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) {
|
||||
GPU_offscreen_free(ofs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPU_framebuffer_restore();
|
||||
|
||||
return ofs;
|
||||
}
|
||||
|
||||
void GPU_offscreen_free(GPUOffScreen *ofs)
|
||||
{
|
||||
if (ofs->fb)
|
||||
GPU_framebuffer_free(ofs->fb);
|
||||
if (ofs->color)
|
||||
GPU_texture_free(ofs->color);
|
||||
if (ofs->depth)
|
||||
GPU_texture_free(ofs->depth);
|
||||
|
||||
MEM_freeN(ofs);
|
||||
}
|
||||
|
||||
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
if (save)
|
||||
GPU_texture_bind_as_framebuffer(ofs->color);
|
||||
else {
|
||||
GPU_framebuffer_bind_no_save(ofs->fb, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore)
|
||||
{
|
||||
if (restore)
|
||||
GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
|
||||
GPU_framebuffer_restore();
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
|
||||
{
|
||||
const int w = GPU_texture_width(ofs->color);
|
||||
const int h = GPU_texture_height(ofs->color);
|
||||
|
||||
if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) {
|
||||
/* For a multi-sample texture,
|
||||
* we need to create an intermediate buffer to blit to,
|
||||
* before its copied using 'glReadPixels' */
|
||||
|
||||
/* not needed since 'ofs' needs to be bound to the framebuffer already */
|
||||
// #define USE_FBO_CTX_SWITCH
|
||||
|
||||
GLuint fbo_blit = 0;
|
||||
GLuint tex_blit = 0;
|
||||
GLenum status;
|
||||
|
||||
/* create texture for new 'fbo_blit' */
|
||||
glGenTextures(1, &tex_blit);
|
||||
if (!tex_blit) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex_blit);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, type, 0);
|
||||
|
||||
#ifdef USE_FBO_CTX_SWITCH
|
||||
/* read from multi-sample buffer */
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object);
|
||||
glFramebufferTexture2DEXT(
|
||||
GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment,
|
||||
GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
|
||||
status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER_EXT);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
|
||||
goto finally;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* write into new single-sample buffer */
|
||||
glGenFramebuffersEXT(1, &fbo_blit);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
|
||||
glFramebufferTexture2DEXT(
|
||||
GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, tex_blit, 0);
|
||||
status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
/* perform the copy */
|
||||
glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
/* read the results */
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
|
||||
|
||||
#ifdef USE_FBO_CTX_SWITCH
|
||||
/* restore the original frame-bufer */
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ofs->color->fb->object);
|
||||
#undef USE_FBO_CTX_SWITCH
|
||||
#endif
|
||||
|
||||
|
||||
finally:
|
||||
/* cleanup */
|
||||
if (tex_blit) {
|
||||
glDeleteTextures(1, &tex_blit);
|
||||
}
|
||||
if (fbo_blit) {
|
||||
glDeleteFramebuffersEXT(1, &fbo_blit);
|
||||
}
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels");
|
||||
}
|
||||
else {
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
|
||||
}
|
||||
}
|
||||
|
||||
int GPU_offscreen_width(const GPUOffScreen *ofs)
|
||||
{
|
||||
return GPU_texture_width(ofs->color);
|
||||
}
|
||||
|
||||
int GPU_offscreen_height(const GPUOffScreen *ofs)
|
||||
{
|
||||
return GPU_texture_height(ofs->color);
|
||||
}
|
||||
|
||||
int GPU_offscreen_color_texture(const GPUOffScreen *ofs)
|
||||
{
|
||||
return GPU_texture_opengl_bindcode(ofs->color);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,10 @@
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "gpu_codegen.h"
|
||||
|
||||
|
||||
783
source/blender/gpu/intern/gpu_shader.c
Normal file
783
source/blender/gpu/intern/gpu_shader.c
Normal file
@@ -0,0 +1,783 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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) 2005 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Brecht Van Lommel.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "GPU_compositing.h"
|
||||
#include "GPU_debug.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
/* TODO(sergey): Find better default values for this constants. */
|
||||
#define MAX_DEFINE_LENGTH 1024
|
||||
#define MAX_EXT_DEFINE_LENGTH 1024
|
||||
|
||||
/* Non-generated shaders */
|
||||
extern char datatoc_gpu_program_smoke_frag_glsl[];
|
||||
extern char datatoc_gpu_program_smoke_color_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
|
||||
extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
|
||||
extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_vert_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_ssao_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_dof_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_dof_vert_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_depth_resolve_glsl[];
|
||||
extern char datatoc_gpu_shader_fx_lib_glsl[];
|
||||
|
||||
static struct GPUShadersGlobal {
|
||||
struct {
|
||||
GPUShader *vsm_store;
|
||||
GPUShader *sep_gaussian_blur;
|
||||
GPUProgram *smoke;
|
||||
GPUProgram *smoke_colored;
|
||||
/* cache for shader fx. Those can exist in combinations so store them here */
|
||||
GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
|
||||
} shaders;
|
||||
} GG = {{NULL}};
|
||||
|
||||
/* GPUShader */
|
||||
|
||||
struct GPUShader {
|
||||
GLuint program; /* handle for full program (links shader stages below) */
|
||||
|
||||
GLuint vertex; /* handle for vertex shader */
|
||||
GLuint geometry; /* handle for geometry shader */
|
||||
GLuint fragment; /* handle for fragment shader */
|
||||
|
||||
int totattrib; /* total number of attributes */
|
||||
int uniforms; /* required uniforms */
|
||||
};
|
||||
|
||||
struct GPUProgram {
|
||||
GPUProgramType type;
|
||||
GLuint prog;
|
||||
};
|
||||
|
||||
static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
|
||||
{
|
||||
int i;
|
||||
int line = 1;
|
||||
|
||||
fprintf(stderr, "GPUShader: %s error:\n", task);
|
||||
|
||||
for (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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s\n", log);
|
||||
}
|
||||
|
||||
static const char *gpu_shader_version(void)
|
||||
{
|
||||
if (GLEW_VERSION_3_2) {
|
||||
if (GLEW_ARB_compatibility) {
|
||||
return "#version 150 compatibility\n";
|
||||
/* highest version that is widely supported
|
||||
* gives us native geometry shaders!
|
||||
* use compatibility profile so we can continue using builtin shader input/output names
|
||||
*/
|
||||
}
|
||||
else {
|
||||
return "#version 130\n";
|
||||
/* latest version that is compatible with existing shaders */
|
||||
}
|
||||
}
|
||||
else if (GLEW_VERSION_3_1) {
|
||||
if (GLEW_ARB_compatibility) {
|
||||
return "#version 140\n";
|
||||
/* also need the ARB_compatibility extension, handled below */
|
||||
}
|
||||
else {
|
||||
return "#version 130\n";
|
||||
/* latest version that is compatible with existing shaders */
|
||||
}
|
||||
}
|
||||
else if (GLEW_VERSION_3_0) {
|
||||
return "#version 130\n";
|
||||
/* GLSL 1.3 has modern syntax/keywords/datatypes so use if available
|
||||
* older features are deprecated but still available without compatibility extension or profile
|
||||
*/
|
||||
}
|
||||
else {
|
||||
return "#version 120\n";
|
||||
/* minimum supported */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_geometry_shader)
|
||||
{
|
||||
/* 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_query_lod) {
|
||||
/* a #version 400 feature, but we use #version 150 maximum so use extension */
|
||||
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
|
||||
}
|
||||
|
||||
if (use_geometry_shader && GPU_geometry_shader_support_via_extension()) {
|
||||
strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n");
|
||||
}
|
||||
|
||||
if (GLEW_VERSION_3_1 && !GLEW_VERSION_3_2 && GLEW_ARB_compatibility) {
|
||||
strcat(defines, "#extension GL_ARB_compatibility: enable\n");
|
||||
}
|
||||
|
||||
if (!GLEW_VERSION_3_1) {
|
||||
if (GLEW_ARB_draw_instanced) {
|
||||
strcat(defines, "#extension GL_ARB_draw_instanced: enable\n");
|
||||
}
|
||||
|
||||
if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) {
|
||||
strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n");
|
||||
/* TODO: maybe require this? shaders become so much nicer */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], bool use_opensubdiv)
|
||||
{
|
||||
/* 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 (GLEW_VERSION_3_0) {
|
||||
/* TODO(merwin): revisit this version check; GLEW_VERSION_3_0 means GL 3.0 or newer */
|
||||
strcat(defines, "#define CLIP_WORKAROUND\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");
|
||||
|
||||
if (GPU_bicubic_bump_support())
|
||||
strcat(defines, "#define BUMP_BICUBIC\n");
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
/* TODO(sergey): Check whether we actually compiling shader for
|
||||
* the OpenSubdiv mesh.
|
||||
*/
|
||||
if (use_opensubdiv) {
|
||||
strcat(defines, "#define USE_OPENSUBDIV\n");
|
||||
|
||||
/* TODO(sergey): not strictly speaking a define, but this is
|
||||
* a global typedef which we don't have better place to define
|
||||
* in yet.
|
||||
*/
|
||||
strcat(defines, "struct VertexData {\n"
|
||||
" vec4 position;\n"
|
||||
" vec3 normal;\n"
|
||||
" vec2 uv;"
|
||||
"};\n");
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(use_opensubdiv);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void GPU_program_bind(GPUProgram *program)
|
||||
{
|
||||
glEnable(program->type);
|
||||
glBindProgramARB(program->type, program->prog);
|
||||
}
|
||||
|
||||
void GPU_program_unbind(GPUProgram *program)
|
||||
{
|
||||
glDisable(program->type);
|
||||
glBindProgramARB(program->type, 0);
|
||||
}
|
||||
|
||||
|
||||
GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code)
|
||||
{
|
||||
/* TODO(merwin): remove ARB program support (recode smoke shader in GLSL) */
|
||||
|
||||
GPUProgram *program;
|
||||
GLint error_pos, is_native;
|
||||
|
||||
if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT))
|
||||
return NULL;
|
||||
|
||||
program = MEM_callocN(sizeof(GPUProgram), "GPUProgram");
|
||||
|
||||
switch (type) {
|
||||
case GPU_PROGRAM_TYPE_FRAGMENT:
|
||||
program->type = GL_FRAGMENT_PROGRAM_ARB;
|
||||
break;
|
||||
}
|
||||
|
||||
/* create the object and set its code string */
|
||||
glGenProgramsARB(1, &program->prog);
|
||||
glBindProgramARB(program->type, program->prog);
|
||||
|
||||
glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code);
|
||||
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
|
||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native);
|
||||
if ((error_pos == -1) && (is_native == 1)) {
|
||||
return program;
|
||||
}
|
||||
else {
|
||||
/* glGetError is set before that, clear it */
|
||||
while (glGetError() != GL_NO_ERROR)
|
||||
;
|
||||
shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1);
|
||||
MEM_freeN(program);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GPU_program_free(GPUProgram *program)
|
||||
{
|
||||
glDeleteProgramsARB(1, &program->prog);
|
||||
MEM_freeN(program);
|
||||
}
|
||||
|
||||
void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w)
|
||||
{
|
||||
glProgramLocalParameter4fARB(program->type, location, x, y, z, w);
|
||||
}
|
||||
|
||||
GPUShader *GPU_shader_create(const char *vertexcode,
|
||||
const char *fragcode,
|
||||
const char *geocode,
|
||||
const char *libcode,
|
||||
const char *defines,
|
||||
int input,
|
||||
int output,
|
||||
int number)
|
||||
{
|
||||
return GPU_shader_create_ex(vertexcode,
|
||||
fragcode,
|
||||
geocode,
|
||||
libcode,
|
||||
defines,
|
||||
input,
|
||||
output,
|
||||
number,
|
||||
GPU_SHADER_FLAGS_NONE);
|
||||
}
|
||||
|
||||
GPUShader *GPU_shader_create_ex(const char *vertexcode,
|
||||
const char *fragcode,
|
||||
const char *geocode,
|
||||
const char *libcode,
|
||||
const char *defines,
|
||||
int input,
|
||||
int output,
|
||||
int number,
|
||||
const int flags)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
/* TODO(sergey): used to add #version 150 to the geometry shader.
|
||||
* Could safely be renamed to "use_geometry_code" since it's very
|
||||
* likely any of geometry code will want to use GLSL 1.5.
|
||||
*/
|
||||
bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0;
|
||||
#else
|
||||
UNUSED_VARS(flags);
|
||||
bool use_opensubdiv = false;
|
||||
#endif
|
||||
GLint status;
|
||||
GLchar log[5000];
|
||||
GLsizei length = 0;
|
||||
GPUShader *shader;
|
||||
char standard_defines[MAX_DEFINE_LENGTH] = "";
|
||||
char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
|
||||
|
||||
if (geocode && !GPU_geometry_shader_support())
|
||||
return NULL;
|
||||
|
||||
shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
|
||||
|
||||
if (vertexcode)
|
||||
shader->vertex = glCreateShader(GL_VERTEX_SHADER);
|
||||
if (fragcode)
|
||||
shader->fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
if (geocode)
|
||||
shader->geometry = glCreateShader(GL_GEOMETRY_SHADER_EXT);
|
||||
|
||||
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, use_opensubdiv);
|
||||
gpu_shader_standard_extensions(standard_extensions, geocode != NULL);
|
||||
|
||||
if (vertexcode) {
|
||||
const char *source[5];
|
||||
/* custom limit, may be too small, beware */
|
||||
int num_source = 0;
|
||||
|
||||
source[num_source++] = gpu_shader_version();
|
||||
source[num_source++] = standard_extensions;
|
||||
source[num_source++] = standard_defines;
|
||||
|
||||
if (defines) source[num_source++] = defines;
|
||||
source[num_source++] = vertexcode;
|
||||
|
||||
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[7];
|
||||
int num_source = 0;
|
||||
|
||||
source[num_source++] = gpu_shader_version();
|
||||
source[num_source++] = standard_extensions;
|
||||
source[num_source++] = standard_defines;
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
/* TODO(sergey): Move to fragment shader source code generation. */
|
||||
if (use_opensubdiv) {
|
||||
source[num_source++] =
|
||||
"#ifdef USE_OPENSUBDIV\n"
|
||||
"in block {\n"
|
||||
" VertexData v;\n"
|
||||
"} inpt;\n"
|
||||
"#endif\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
if (defines) source[num_source++] = defines;
|
||||
if (libcode) source[num_source++] = libcode;
|
||||
source[num_source++] = fragcode;
|
||||
|
||||
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++] = standard_extensions;
|
||||
source[num_source++] = standard_defines;
|
||||
|
||||
if (defines) source[num_source++] = defines;
|
||||
source[num_source++] = geocode;
|
||||
|
||||
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 (!use_opensubdiv) {
|
||||
GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
if (use_opensubdiv) {
|
||||
glBindAttribLocation(shader->program, 0, "position");
|
||||
glBindAttribLocation(shader->program, 1, "normal");
|
||||
GPU_shader_geometry_stage_primitive_io(shader,
|
||||
GL_LINES_ADJACENCY_EXT,
|
||||
GL_TRIANGLE_STRIP,
|
||||
4);
|
||||
}
|
||||
#endif
|
||||
|
||||
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 (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;
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
/* TODO(sergey): Find a better place for this. */
|
||||
if (use_opensubdiv && GLEW_VERSION_4_1) {
|
||||
glProgramUniform1i(shader->program,
|
||||
glGetUniformLocation(shader->program, "FVarDataBuffer"),
|
||||
31); /* GL_TEXTURE31 */
|
||||
}
|
||||
#endif
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
void GPU_shader_bind(GPUShader *shader)
|
||||
{
|
||||
GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind");
|
||||
glUseProgram(shader->program);
|
||||
GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind");
|
||||
}
|
||||
|
||||
void GPU_shader_unbind(void)
|
||||
{
|
||||
GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind");
|
||||
glUseProgram(0);
|
||||
GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind");
|
||||
}
|
||||
|
||||
void GPU_shader_free(GPUShader *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);
|
||||
MEM_freeN(shader);
|
||||
}
|
||||
|
||||
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
|
||||
{
|
||||
return glGetUniformLocation(shader->program, name);
|
||||
}
|
||||
|
||||
void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value)
|
||||
{
|
||||
if (location == -1 || value == NULL)
|
||||
return;
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
|
||||
|
||||
if (length == 1) glUniform1fv(location, arraysize, value);
|
||||
else if (length == 2) glUniform2fv(location, arraysize, value);
|
||||
else if (length == 3) glUniform3fv(location, arraysize, value);
|
||||
else if (length == 4) glUniform4fv(location, arraysize, value);
|
||||
else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value);
|
||||
else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value);
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
|
||||
}
|
||||
|
||||
void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
|
||||
|
||||
if (length == 1) glUniform1iv(location, arraysize, value);
|
||||
else if (length == 2) glUniform2iv(location, arraysize, value);
|
||||
else if (length == 3) glUniform3iv(location, arraysize, value);
|
||||
else if (length == 4) glUniform4iv(location, arraysize, value);
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
|
||||
}
|
||||
|
||||
void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value));
|
||||
}
|
||||
|
||||
void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number)
|
||||
{
|
||||
if (GPU_geometry_shader_support_via_extension()) {
|
||||
/* geometry shaders must provide this info themselves for #version 150 and up */
|
||||
glProgramParameteriEXT(shader->program, GL_GEOMETRY_INPUT_TYPE_EXT, input);
|
||||
glProgramParameteriEXT(shader->program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
|
||||
glProgramParameteriEXT(shader->program, GL_GEOMETRY_VERTICES_OUT_EXT, number);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
|
||||
{
|
||||
GLenum arbnumber;
|
||||
int number = GPU_texture_bound_number(tex);
|
||||
int bindcode = GPU_texture_opengl_bindcode(tex);
|
||||
int target = GPU_texture_target(tex);
|
||||
|
||||
if (number >= GPU_max_textures()) {
|
||||
fprintf(stderr, "Not enough texture slots.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (number == -1)
|
||||
return;
|
||||
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture");
|
||||
|
||||
arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
|
||||
|
||||
if (number != 0) glActiveTexture(arbnumber);
|
||||
if (bindcode != 0)
|
||||
glBindTexture(target, bindcode);
|
||||
else
|
||||
GPU_invalid_tex_bind(target);
|
||||
glUniform1i(location, number);
|
||||
glEnable(target);
|
||||
if (number != 0) glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture");
|
||||
}
|
||||
|
||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
|
||||
{
|
||||
int index;
|
||||
|
||||
GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name));
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
|
||||
{
|
||||
GPUShader *retval = NULL;
|
||||
|
||||
switch (shader) {
|
||||
case GPU_SHADER_VSM_STORE:
|
||||
if (!GG.shaders.vsm_store)
|
||||
GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL, NULL, 0, 0, 0);
|
||||
retval = GG.shaders.vsm_store;
|
||||
break;
|
||||
case GPU_SHADER_SEP_GAUSSIAN_BLUR:
|
||||
if (!GG.shaders.sep_gaussian_blur)
|
||||
GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL, NULL, 0, 0, 0);
|
||||
retval = GG.shaders.sep_gaussian_blur;
|
||||
break;
|
||||
}
|
||||
|
||||
if (retval == NULL)
|
||||
printf("Unable to create a GPUShader for builtin shader: %u\n", shader);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program)
|
||||
{
|
||||
GPUProgram *retval = NULL;
|
||||
|
||||
switch (program) {
|
||||
case GPU_PROGRAM_SMOKE:
|
||||
if (!GG.shaders.smoke)
|
||||
GG.shaders.smoke = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl);
|
||||
retval = GG.shaders.smoke;
|
||||
break;
|
||||
case GPU_PROGRAM_SMOKE_COLORED:
|
||||
if (!GG.shaders.smoke_colored)
|
||||
GG.shaders.smoke_colored = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl);
|
||||
retval = GG.shaders.smoke_colored;
|
||||
break;
|
||||
}
|
||||
|
||||
if (retval == NULL)
|
||||
printf("Unable to create a GPUProgram for builtin program: %u\n", program);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define MAX_DEFINES 100
|
||||
|
||||
GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp)
|
||||
{
|
||||
int offset;
|
||||
char defines[MAX_DEFINES] = "";
|
||||
/* avoid shaders out of range */
|
||||
if (effects >= MAX_FX_SHADERS)
|
||||
return NULL;
|
||||
|
||||
offset = 2 * effects;
|
||||
|
||||
if (persp) {
|
||||
offset += 1;
|
||||
strcat(defines, "#define PERSP_MATRIX\n");
|
||||
}
|
||||
|
||||
if (!GG.shaders.fx_shaders[offset]) {
|
||||
GPUShader *shader;
|
||||
|
||||
switch (effects) {
|
||||
case GPU_SHADER_FX_SSAO:
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE:
|
||||
strcat(defines, "#define FIRST_PASS\n");
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
|
||||
strcat(defines, "#define SECOND_PASS\n");
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
|
||||
strcat(defines, "#define THIRD_PASS\n");
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
|
||||
strcat(defines, "#define FOURTH_PASS\n");
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
|
||||
strcat(defines, "#define FIFTH_PASS\n");
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE:
|
||||
strcat(defines, "#define FIRST_PASS\n");
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO:
|
||||
strcat(defines, "#define SECOND_PASS\n");
|
||||
shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl,
|
||||
defines, GL_POINTS, GL_TRIANGLE_STRIP, 4);
|
||||
GG.shaders.fx_shaders[offset] = shader;
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE:
|
||||
strcat(defines, "#define THIRD_PASS\n");
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case GPU_SHADER_FX_DEPTH_RESOLVE:
|
||||
GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return GG.shaders.fx_shaders[offset];
|
||||
}
|
||||
|
||||
|
||||
void GPU_shader_free_builtin_shaders(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (GG.shaders.vsm_store) {
|
||||
GPU_shader_free(GG.shaders.vsm_store);
|
||||
GG.shaders.vsm_store = NULL;
|
||||
}
|
||||
|
||||
if (GG.shaders.sep_gaussian_blur) {
|
||||
GPU_shader_free(GG.shaders.sep_gaussian_blur);
|
||||
GG.shaders.sep_gaussian_blur = NULL;
|
||||
}
|
||||
|
||||
if (GG.shaders.smoke) {
|
||||
GPU_program_free(GG.shaders.smoke);
|
||||
GG.shaders.smoke = NULL;
|
||||
}
|
||||
|
||||
if (GG.shaders.smoke_colored) {
|
||||
GPU_program_free(GG.shaders.smoke_colored);
|
||||
GG.shaders.smoke_colored = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2 * MAX_FX_SHADERS; i++) {
|
||||
if (GG.shaders.fx_shaders[i]) {
|
||||
GPU_shader_free(GG.shaders.fx_shaders[i]);
|
||||
GG.shaders.fx_shaders[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
762
source/blender/gpu/intern/gpu_texture.c
Normal file
762
source/blender/gpu/intern/gpu_texture.c
Normal file
@@ -0,0 +1,762 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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) 2005 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Brecht Van Lommel.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "GPU_debug.h"
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
static struct GPUTextureGlobal {
|
||||
GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
|
||||
GPUTexture *invalid_tex_2D;
|
||||
GPUTexture *invalid_tex_3D;
|
||||
} GG = {NULL, NULL, NULL};
|
||||
|
||||
/* GPUTexture */
|
||||
|
||||
struct GPUTexture {
|
||||
int w, h; /* width/height */
|
||||
int number; /* number for multitexture binding */
|
||||
int refcount; /* reference count */
|
||||
GLenum target; /* GL_TEXTURE_* */
|
||||
GLenum target_base; /* same as target, (but no multisample) */
|
||||
GLuint bindcode; /* opengl identifier for texture */
|
||||
int fromblender; /* we got the texture from Blender */
|
||||
|
||||
GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
|
||||
int fb_attachment; /* slot the texture is attached to */
|
||||
int depth; /* is a depth texture? if 3D how deep? */
|
||||
};
|
||||
|
||||
static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels)
|
||||
{
|
||||
unsigned char *pixels, *p;
|
||||
const float *fp = fpixels;
|
||||
const int len = 4 * length;
|
||||
int a;
|
||||
|
||||
p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels");
|
||||
|
||||
for (a = 0; a < len; a++, p++, fp++)
|
||||
*p = FTOCHAR((*fp));
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
|
||||
{
|
||||
void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
|
||||
|
||||
if (target == GL_TEXTURE_1D)
|
||||
glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
|
||||
else
|
||||
glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
MEM_freeN(pixels);
|
||||
}
|
||||
|
||||
static GPUTexture *GPU_texture_create_nD(
|
||||
int w, int h, int n, const float *fpixels, int depth,
|
||||
GPUHDRType hdr_type, int components, int samples,
|
||||
char err_out[256])
|
||||
{
|
||||
GPUTexture *tex;
|
||||
GLenum type, format, internalformat;
|
||||
void *pixels = NULL;
|
||||
|
||||
if (samples) {
|
||||
CLAMP_MAX(samples, GPU_max_color_texture_samples());
|
||||
}
|
||||
|
||||
tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
|
||||
tex->w = w;
|
||||
tex->h = h;
|
||||
tex->number = -1;
|
||||
tex->refcount = 1;
|
||||
tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
|
||||
tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D;
|
||||
tex->depth = depth;
|
||||
tex->fb_attachment = -1;
|
||||
|
||||
glGenTextures(1, &tex->bindcode);
|
||||
|
||||
if (!tex->bindcode) {
|
||||
if (err_out) {
|
||||
BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d",
|
||||
(int)glGetError());
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "GPUTexture: texture create failed: %d\n",
|
||||
(int)glGetError());
|
||||
}
|
||||
GPU_texture_free(tex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!GPU_full_non_power_of_two_support()) {
|
||||
tex->w = power_of_2_max_i(tex->w);
|
||||
tex->h = power_of_2_max_i(tex->h);
|
||||
}
|
||||
|
||||
tex->number = 0;
|
||||
glBindTexture(tex->target, tex->bindcode);
|
||||
|
||||
if (depth) {
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
format = GL_DEPTH_COMPONENT;
|
||||
internalformat = GL_DEPTH_COMPONENT;
|
||||
}
|
||||
else {
|
||||
type = GL_FLOAT;
|
||||
|
||||
if (components == 4) {
|
||||
format = GL_RGBA;
|
||||
switch (hdr_type) {
|
||||
case GPU_HDR_NONE:
|
||||
internalformat = GL_RGBA8;
|
||||
break;
|
||||
/* the following formats rely on ARB_texture_float or OpenGL 3.0 */
|
||||
case GPU_HDR_HALF_FLOAT:
|
||||
internalformat = GL_RGBA16F_ARB;
|
||||
break;
|
||||
case GPU_HDR_FULL_FLOAT:
|
||||
internalformat = GL_RGBA32F_ARB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (components == 2) {
|
||||
/* these formats rely on ARB_texture_rg or OpenGL 3.0 */
|
||||
format = GL_RG;
|
||||
switch (hdr_type) {
|
||||
case GPU_HDR_NONE:
|
||||
internalformat = GL_RG8;
|
||||
break;
|
||||
case GPU_HDR_HALF_FLOAT:
|
||||
internalformat = GL_RG16F;
|
||||
break;
|
||||
case GPU_HDR_FULL_FLOAT:
|
||||
internalformat = GL_RG32F;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fpixels && hdr_type == GPU_HDR_NONE) {
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
pixels = GPU_texture_convert_pixels(w*h, fpixels);
|
||||
}
|
||||
}
|
||||
|
||||
if (tex->target == GL_TEXTURE_1D) {
|
||||
glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
|
||||
|
||||
if (fpixels) {
|
||||
glTexSubImage1D(tex->target, 0, 0, w, format, type,
|
||||
pixels ? pixels : fpixels);
|
||||
|
||||
if (tex->w > w)
|
||||
GPU_glTexSubImageEmpty(tex->target, format, w, 0,
|
||||
tex->w-w, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (samples) {
|
||||
glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true);
|
||||
}
|
||||
else {
|
||||
glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
|
||||
format, type, NULL);
|
||||
}
|
||||
|
||||
if (fpixels) {
|
||||
glTexSubImage2D(tex->target, 0, 0, 0, w, h,
|
||||
format, type, pixels ? pixels : fpixels);
|
||||
|
||||
if (tex->w > w)
|
||||
GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h);
|
||||
if (tex->h > h)
|
||||
GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h);
|
||||
}
|
||||
}
|
||||
|
||||
if (pixels)
|
||||
MEM_freeN(pixels);
|
||||
|
||||
if (depth) {
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
|
||||
}
|
||||
else {
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
|
||||
if (tex->target_base != GL_TEXTURE_1D) {
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
else
|
||||
glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
|
||||
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels)
|
||||
{
|
||||
GPUTexture *tex;
|
||||
GLenum type, format, internalformat;
|
||||
void *pixels = NULL;
|
||||
int r_width;
|
||||
bool rescale = false;
|
||||
|
||||
if (!GLEW_VERSION_1_2)
|
||||
return NULL;
|
||||
|
||||
tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
|
||||
tex->w = w;
|
||||
tex->h = h;
|
||||
tex->depth = depth;
|
||||
tex->number = -1;
|
||||
tex->refcount = 1;
|
||||
tex->target = GL_TEXTURE_3D;
|
||||
tex->target_base = GL_TEXTURE_3D;
|
||||
|
||||
glGenTextures(1, &tex->bindcode);
|
||||
|
||||
if (!tex->bindcode) {
|
||||
fprintf(stderr, "GPUTexture: texture create failed: %d\n",
|
||||
(int)glGetError());
|
||||
GPU_texture_free(tex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tex->number = 0;
|
||||
glBindTexture(tex->target, tex->bindcode);
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture");
|
||||
|
||||
type = GL_FLOAT;
|
||||
if (channels == 4) {
|
||||
format = GL_RGBA;
|
||||
internalformat = GL_RGBA8;
|
||||
}
|
||||
else {
|
||||
format = GL_RED;
|
||||
internalformat = GL_INTENSITY8;
|
||||
}
|
||||
|
||||
/* 3D textures are quite heavy, test if it's possible to create them first */
|
||||
glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
|
||||
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
|
||||
|
||||
while (r_width == 0) {
|
||||
rescale = true;
|
||||
tex->w /= 2;
|
||||
tex->h /= 2;
|
||||
tex->depth /= 2;
|
||||
glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
|
||||
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
|
||||
}
|
||||
|
||||
/* really unlikely to happen but keep this just in case */
|
||||
tex->w = max_ii(tex->w, 1);
|
||||
tex->h = max_ii(tex->h, 1);
|
||||
tex->depth = max_ii(tex->depth, 1);
|
||||
|
||||
#if 0
|
||||
if (fpixels)
|
||||
pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
|
||||
#endif
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D");
|
||||
|
||||
/* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it
|
||||
* for gooseberry */
|
||||
if (rescale && fpixels) {
|
||||
unsigned int i, j, k;
|
||||
unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth;
|
||||
float *tex3d = MEM_mallocN(channels * sizeof(float)*tex->w*tex->h*tex->depth, "tex3d");
|
||||
|
||||
GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
|
||||
|
||||
for (k = 0; k < tex->depth; k++) {
|
||||
for (j = 0; j < tex->h; j++) {
|
||||
for (i = 0; i < tex->w; i++) {
|
||||
/* obviously doing nearest filtering here, it's going to be slow in any case, let's not make it worse */
|
||||
float xb = i * xf;
|
||||
float yb = j * yf;
|
||||
float zb = k * zf;
|
||||
unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
|
||||
unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
|
||||
|
||||
if (channels == 4) {
|
||||
tex3d[offset * 4] = fpixels[offset_orig * 4];
|
||||
tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
|
||||
tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
|
||||
tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
|
||||
}
|
||||
else
|
||||
tex3d[offset] = fpixels[offset_orig];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d);
|
||||
|
||||
MEM_freeN(tex3d);
|
||||
}
|
||||
else {
|
||||
if (fpixels) {
|
||||
glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels);
|
||||
GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (pixels)
|
||||
MEM_freeN(pixels);
|
||||
|
||||
GPU_texture_unbind(tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, double time, int mipmap)
|
||||
{
|
||||
GPUTexture *tex;
|
||||
GLint w, h, border, bindcode;
|
||||
|
||||
GPU_update_image_time(ima, time);
|
||||
/* this binds a texture, so that's why to restore it to 0 */
|
||||
bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap, is_data);
|
||||
|
||||
if (ima->gputexture) {
|
||||
ima->gputexture->bindcode = bindcode;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return ima->gputexture;
|
||||
}
|
||||
|
||||
tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
|
||||
tex->bindcode = bindcode;
|
||||
tex->number = -1;
|
||||
tex->refcount = 1;
|
||||
tex->target = GL_TEXTURE_2D;
|
||||
tex->target_base = GL_TEXTURE_2D;
|
||||
tex->fromblender = 1;
|
||||
|
||||
ima->gputexture= tex;
|
||||
|
||||
if (!glIsTexture(tex->bindcode)) {
|
||||
GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
|
||||
}
|
||||
else {
|
||||
glBindTexture(GL_TEXTURE_2D, tex->bindcode);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
|
||||
|
||||
tex->w = w - border;
|
||||
tex->h = h - border;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
|
||||
{
|
||||
GPUTexture *tex = prv->gputexture[0];
|
||||
GLint w, h;
|
||||
GLuint bindcode = 0;
|
||||
|
||||
if (tex)
|
||||
bindcode = tex->bindcode;
|
||||
|
||||
/* this binds a texture, so that's why we restore it to 0 */
|
||||
if (bindcode == 0) {
|
||||
GPU_create_gl_tex(&bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], mipmap, 0, NULL);
|
||||
}
|
||||
if (tex) {
|
||||
tex->bindcode = bindcode;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return tex;
|
||||
}
|
||||
|
||||
tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
|
||||
tex->bindcode = bindcode;
|
||||
tex->number = -1;
|
||||
tex->refcount = 1;
|
||||
tex->target = GL_TEXTURE_2D;
|
||||
tex->target_base = GL_TEXTURE_2D;
|
||||
|
||||
prv->gputexture[0] = tex;
|
||||
|
||||
if (!glIsTexture(tex->bindcode)) {
|
||||
GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
|
||||
}
|
||||
else {
|
||||
glBindTexture(GL_TEXTURE_2D, tex->bindcode);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
|
||||
|
||||
tex->w = w;
|
||||
tex->h = h;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return tex;
|
||||
|
||||
}
|
||||
|
||||
GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256])
|
||||
{
|
||||
GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out);
|
||||
|
||||
if (tex)
|
||||
GPU_texture_unbind(tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256])
|
||||
{
|
||||
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out);
|
||||
|
||||
if (tex)
|
||||
GPU_texture_unbind(tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256])
|
||||
{
|
||||
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out);
|
||||
|
||||
if (tex)
|
||||
GPU_texture_unbind(tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
|
||||
{
|
||||
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out);
|
||||
|
||||
if (tex)
|
||||
GPU_texture_unbind(tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256])
|
||||
{
|
||||
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out);
|
||||
|
||||
if (tex)
|
||||
GPU_texture_unbind(tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
/**
|
||||
* A shadow map for VSM needs two components (depth and depth^2)
|
||||
*/
|
||||
GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
|
||||
{
|
||||
GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out);
|
||||
|
||||
if (tex) {
|
||||
/* Now we tweak some of the settings */
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
GPU_texture_unbind(tex);
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
|
||||
{
|
||||
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
|
||||
|
||||
if (tex) {
|
||||
/* Now we tweak some of the settings */
|
||||
if (repeat) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
GPU_texture_unbind(tex);
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256])
|
||||
{
|
||||
GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
|
||||
|
||||
if (tex) {
|
||||
/* Now we tweak some of the settings */
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
GPU_texture_unbind(tex);
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void GPU_invalid_tex_init(void)
|
||||
{
|
||||
const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
|
||||
GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
|
||||
GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
|
||||
GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
|
||||
}
|
||||
|
||||
void GPU_invalid_tex_bind(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case GL_TEXTURE_1D:
|
||||
glBindTexture(GL_TEXTURE_1D, GG.invalid_tex_1D->bindcode);
|
||||
break;
|
||||
case GL_TEXTURE_2D:
|
||||
glBindTexture(GL_TEXTURE_2D, GG.invalid_tex_2D->bindcode);
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
glBindTexture(GL_TEXTURE_3D, GG.invalid_tex_3D->bindcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_invalid_tex_free(void)
|
||||
{
|
||||
if (GG.invalid_tex_1D)
|
||||
GPU_texture_free(GG.invalid_tex_1D);
|
||||
if (GG.invalid_tex_2D)
|
||||
GPU_texture_free(GG.invalid_tex_2D);
|
||||
if (GG.invalid_tex_3D)
|
||||
GPU_texture_free(GG.invalid_tex_3D);
|
||||
}
|
||||
|
||||
|
||||
void GPU_texture_bind(GPUTexture *tex, int number)
|
||||
{
|
||||
GLenum arbnumber;
|
||||
|
||||
if (number >= GPU_max_textures()) {
|
||||
fprintf(stderr, "Not enough texture slots.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((G.debug & G_DEBUG)) {
|
||||
if (tex->fb && GPU_framebuffer_bound(tex->fb)) {
|
||||
fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (number < 0)
|
||||
return;
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind");
|
||||
|
||||
arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
|
||||
if (number != 0) glActiveTexture(arbnumber);
|
||||
if (tex->bindcode != 0) {
|
||||
glBindTexture(tex->target, tex->bindcode);
|
||||
}
|
||||
else
|
||||
GPU_invalid_tex_bind(tex->target);
|
||||
glEnable(tex->target);
|
||||
if (number != 0) glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
tex->number = number;
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind");
|
||||
}
|
||||
|
||||
void GPU_texture_unbind(GPUTexture *tex)
|
||||
{
|
||||
GLenum arbnumber;
|
||||
|
||||
if (tex->number >= GPU_max_textures()) {
|
||||
fprintf(stderr, "Not enough texture slots.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tex->number == -1)
|
||||
return;
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
|
||||
|
||||
arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
|
||||
if (tex->number != 0) glActiveTexture(arbnumber);
|
||||
glBindTexture(tex->target, 0);
|
||||
glDisable(tex->target_base);
|
||||
if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
tex->number = -1;
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
|
||||
}
|
||||
|
||||
int GPU_texture_bound_number(GPUTexture *tex)
|
||||
{
|
||||
return tex->number;
|
||||
}
|
||||
|
||||
void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
|
||||
{
|
||||
GLenum arbnumber;
|
||||
|
||||
if (tex->number >= GPU_max_textures()) {
|
||||
fprintf(stderr, "Not enough texture slots.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tex->number == -1)
|
||||
return;
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
|
||||
|
||||
arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
|
||||
if (tex->number != 0) glActiveTexture(arbnumber);
|
||||
|
||||
if (tex->depth) {
|
||||
if (compare)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
||||
else
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
}
|
||||
|
||||
if (use_filter) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
|
||||
}
|
||||
|
||||
void GPU_texture_free(GPUTexture *tex)
|
||||
{
|
||||
tex->refcount--;
|
||||
|
||||
if (tex->refcount < 0)
|
||||
fprintf(stderr, "GPUTexture: negative refcount\n");
|
||||
|
||||
if (tex->refcount == 0) {
|
||||
if (tex->fb)
|
||||
GPU_framebuffer_texture_detach(tex);
|
||||
if (tex->bindcode && !tex->fromblender)
|
||||
glDeleteTextures(1, &tex->bindcode);
|
||||
|
||||
MEM_freeN(tex);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_texture_ref(GPUTexture *tex)
|
||||
{
|
||||
tex->refcount++;
|
||||
}
|
||||
|
||||
int GPU_texture_target(const GPUTexture *tex)
|
||||
{
|
||||
return tex->target;
|
||||
}
|
||||
|
||||
int GPU_texture_width(const GPUTexture *tex)
|
||||
{
|
||||
return tex->w;
|
||||
}
|
||||
|
||||
int GPU_texture_height(const GPUTexture *tex)
|
||||
{
|
||||
return tex->h;
|
||||
}
|
||||
|
||||
int GPU_texture_depth(const GPUTexture *tex)
|
||||
{
|
||||
return tex->depth;
|
||||
}
|
||||
|
||||
int GPU_texture_opengl_bindcode(const GPUTexture *tex)
|
||||
{
|
||||
return tex->bindcode;
|
||||
}
|
||||
|
||||
GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
|
||||
{
|
||||
return tex->fb;
|
||||
}
|
||||
|
||||
int GPU_texture_framebuffer_attachment(GPUTexture *tex)
|
||||
{
|
||||
return tex->fb_attachment;
|
||||
}
|
||||
|
||||
void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment)
|
||||
{
|
||||
tex->fb = fb;
|
||||
tex->fb_attachment = attachment;
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_compositing.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
|
||||
#include "../mathutils/mathutils.h"
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
#include "BL_BlenderShader.h"
|
||||
#include "BL_Material.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "RAS_BucketManager.h"
|
||||
#include "RAS_MeshObject.h"
|
||||
|
||||
@@ -51,8 +51,9 @@
|
||||
#include "RAS_StorageVBO.h"
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_shader.h"
|
||||
|
||||
extern "C"{
|
||||
#include "BLF_api.h"
|
||||
|
||||
Reference in New Issue
Block a user