diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-05-13 23:12:32 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-05-13 23:44:57 +0300 |
commit | 402442997a39067d6f84538770665f1baf206f79 (patch) | |
tree | c0fbdfb7c68c7df3fc0e0109677a8c1961242152 | |
parent | ddf308b04adf1276f6c0972ade35d60d8cb57bcd (diff) |
GPUTexture: Add Texture Buffer support.
This is needed by opensubdiv and can be helpfull in a lot of other cases.
-rw-r--r-- | source/blender/gpu/GPU_texture.h | 50 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_texture.c | 120 |
2 files changed, 145 insertions, 25 deletions
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index a64b0a0a862..cc66b5dbf9b 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -39,6 +39,7 @@ extern "C" { struct Image; struct ImageUser; struct PreviewImage; +struct Gwn_VertBuf; struct GPUFrameBuffer; typedef struct GPUTexture GPUTexture; @@ -62,38 +63,36 @@ typedef struct GPUTexture GPUTexture; * specification. */ typedef enum GPUTextureFormat { /* Formats texture & renderbuffer */ + GPU_RGBA8UI, + GPU_RGBA8I, + GPU_RGBA8, + GPU_RGBA32UI, + GPU_RGBA32I, GPU_RGBA32F, + GPU_RGBA16UI, + GPU_RGBA16I, GPU_RGBA16F, - GPU_RGBA8, + GPU_RGBA16, + GPU_RG8UI, + GPU_RG8I, + GPU_RG8, + GPU_RG32UI, + GPU_RG32I, GPU_RG32F, - GPU_RG16F, + GPU_RG16UI, GPU_RG16I, + GPU_RG16F, GPU_RG16, - GPU_R32F, - GPU_R32UI, - GPU_R16F, - GPU_R16I, - GPU_R16UI, - GPU_RG8, + GPU_R8UI, + GPU_R8I, GPU_R8, -#if 0 - GPU_RGBA32I, - GPU_RGBA32UI, - GPU_RGBA16, - GPU_RGBA16I, - GPU_RGBA16UI, - GPU_RGBA8I, - GPU_RGBA8UI, - GPU_RG32I, - GPU_RG32UI, - GPU_RG16UI, - GPU_RG8I, - GPU_RG8UI, + GPU_R32UI, GPU_R32I, - GPU_R16, - GPU_R8I, - GPU_R8UI, -#endif + GPU_R32F, + GPU_R16UI, + GPU_R16I, + GPU_R16F, + GPU_R16, /* Max texture buffer format. */ /* Special formats texture & renderbuffer */ #if 0 @@ -157,6 +156,7 @@ GPUTexture *GPU_texture_create_3D( int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_create_cube( int w, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_from_vertbuf(struct Gwn_VertBuf *vert); GPUTexture *GPU_texture_from_blender( struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap); diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 19e26dcce8c..3961278ad1a 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -35,6 +35,7 @@ #include "BKE_global.h" +#include "GPU_batch.h" #include "GPU_debug.h" #include "GPU_draw.h" #include "GPU_extensions.h" @@ -608,6 +609,57 @@ static GPUTexture *GPU_texture_cube_create( return tex; } +/* Special buffer textures. data_type must be compatible with the buffer content. */ +static GPUTexture *GPU_texture_create_buffer(GPUTextureFormat data_type, const GLuint buffer) +{ + GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->number = -1; + tex->refcount = 1; + tex->format = data_type; + tex->components = gpu_texture_get_component_count(data_type); + tex->format_flag = 0; + tex->target_base = tex->target = GL_TEXTURE_BUFFER; + + GLenum format, internalformat, data_format; + internalformat = gpu_texture_get_format(tex->components, data_type, &format, &data_format, + &tex->format_flag, &tex->bytesize); + + if (!(ELEM(data_type, GPU_R8, GPU_R16) || + ELEM(data_type, GPU_R16F, GPU_R32F) || + ELEM(data_type, GPU_R8I, GPU_R16I, GPU_R32I) || + ELEM(data_type, GPU_R8UI, GPU_R16UI, GPU_R32UI) || + ELEM(data_type, GPU_RG8, GPU_RG16) || + ELEM(data_type, GPU_RG16F, GPU_RG32F) || + ELEM(data_type, GPU_RG8I, GPU_RG16I, GPU_RG32I) || + ELEM(data_type, GPU_RG8UI, GPU_RG16UI, GPU_RG32UI) || + //ELEM(data_type, GPU_RGB32F, GPU_RGB32I, GPU_RGB32UI) || /* Not available until gl 4.0 */ + ELEM(data_type, GPU_RGBA8, GPU_RGBA16) || + ELEM(data_type, GPU_RGBA16F, GPU_RGBA32F) || + ELEM(data_type, GPU_RGBA8I, GPU_RGBA16I, GPU_RGBA32I) || + ELEM(data_type, GPU_RGBA8UI, GPU_RGBA16UI, GPU_RGBA32UI))) + { + fprintf(stderr, "GPUTexture: invalid format for texture buffer"); + GPU_texture_free(tex); + return NULL; + } + + /* Generate Texture object */ + glGenTextures(1, &tex->bindcode); + + if (!tex->bindcode) { + fprintf(stderr, "GPUTexture: texture create failed"); + GPU_texture_free(tex); + BLI_assert(0 && "glGenTextures failled: Are you sure a valid OGL context is active on this thread?"); + return NULL; + } + + glBindTexture(tex->target, tex->bindcode); + glTexBuffer(tex->target, internalformat, buffer); + glBindTexture(tex->target, 0); + + return tex; +} + GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data, double UNUSED(time), int mipmap) { int gputt; @@ -768,6 +820,74 @@ GPUTexture *GPU_texture_create_cube( data_type, err_out); } +GPUTexture *GPU_texture_create_from_vertbuf(Gwn_VertBuf *vert) +{ + Gwn_VertFormat *format = &vert->format; + Gwn_VertAttr *attr = &format->attribs[0]; + + /* Detect incompatible cases (not supported by texture buffers) */ + BLI_assert(format->attrib_ct == 1 && vert->vbo_id != 0); + BLI_assert(attr->comp_ct != 3); /* Not until OGL 4.0 */ + BLI_assert(attr->comp_type != GWN_COMP_I10); + BLI_assert(attr->fetch_mode != GWN_FETCH_INT_TO_FLOAT); + + unsigned int byte_per_comp = attr->sz / attr->comp_ct; + bool is_uint = ELEM(attr->comp_type, GWN_COMP_U8, GWN_COMP_U16, GWN_COMP_U32); + + /* Cannot fetch signed int or 32bit ints as normalized float. */ + if (attr->fetch_mode == GWN_FETCH_INT_TO_FLOAT_UNIT) { + BLI_assert(is_uint || byte_per_comp <= 2); + } + + GPUTextureFormat data_type; + switch (attr->fetch_mode) { + case GWN_FETCH_FLOAT: + switch (attr->comp_ct) { + case 1: data_type = GPU_R32F; break; + case 2: data_type = GPU_RG32F; break; + // case 3: data_type = GPU_RGB32F; break; /* Not supported */ + default: data_type = GPU_RGBA32F; break; + } + break; + case GWN_FETCH_INT: + switch (attr->comp_ct) { + case 1: + switch (byte_per_comp) { + case 1: data_type = (is_uint) ? GPU_R8UI : GPU_R8I; break; + case 2: data_type = (is_uint) ? GPU_R16UI : GPU_R16I; break; + default: data_type = (is_uint) ? GPU_R32UI : GPU_R32I; break; + } + break; + case 2: + switch (byte_per_comp) { + case 1: data_type = (is_uint) ? GPU_RG8UI : GPU_RG8I; break; + case 2: data_type = (is_uint) ? GPU_RG16UI : GPU_RG16I; break; + default: data_type = (is_uint) ? GPU_RG32UI : GPU_RG32I; break; + } + break; + default: + switch (byte_per_comp) { + case 1: data_type = (is_uint) ? GPU_RGBA8UI : GPU_RGBA8I; break; + case 2: data_type = (is_uint) ? GPU_RGBA16UI : GPU_RGBA16I; break; + default: data_type = (is_uint) ? GPU_RGBA32UI : GPU_RGBA32I; break; + } + break; + } + break; + case GWN_FETCH_INT_TO_FLOAT_UNIT: + switch (attr->comp_ct) { + case 1: data_type = (byte_per_comp == 1) ? GPU_R8 : GPU_R16; break; + case 2: data_type = (byte_per_comp == 1) ? GPU_RG8 : GPU_RG16; break; + default: data_type = (byte_per_comp == 1) ? GPU_RGBA8 : GPU_RGBA16; break; + } + break; + default: + BLI_assert(0); + } + + return GPU_texture_create_buffer(data_type, vert->vbo_id); +} + void GPU_texture_update(GPUTexture *tex, const float *pixels) { BLI_assert(tex->format > -1); |