GLRefactor: Refactor bf_blenfont to use GPUTexture instead of raw GL calls and types.

In an effort to centralize all opengl calls in the codebase, this patch replaces
the raw opengl calls in bf_blenfont with GPUTexture so it's no longer depended
on opengl headers.

reviewer: Brecht

Differential Revision: https://developer.blender.org/D3483
This commit is contained in:
Ray molenkamp 2018-06-21 18:35:37 -06:00
parent 4f83fd4cf8
commit 84ae0fe3a5
Notes: blender-bot 2023-02-14 11:28:43 +01:00
Referenced by issue #55588, BLF Text shadow is broken
Referenced by issue #55582, [2.8] Clear weights for all Shape keys crash
5 changed files with 142 additions and 55 deletions

View File

@ -183,16 +183,13 @@ void blf_batch_draw(void)
if (g_batch.glyph_len == 0)
return;
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
GPU_blend(true);
GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* We need to flush widget base first to ensure correct ordering. */
UI_widgetbase_draw_cache_flush();
BLI_assert(g_batch.tex_bind_state != 0); /* must still be valid */
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, g_batch.tex_bind_state);
GPU_texture_bind(g_batch.tex_bind_state, 0);
GWN_vertbuf_vertex_count_set(g_batch.verts, g_batch.glyph_len);
GWN_vertbuf_use(g_batch.verts); /* send data */
@ -201,7 +198,7 @@ void blf_batch_draw(void)
GWN_batch_uniform_1i(g_batch.batch, "glyph", 0);
GWN_batch_draw(g_batch.batch);
glDisable(GL_BLEND);
GPU_blend(false);
/* restart to 1st vertex data pointers */
GWN_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);

View File

@ -57,6 +57,7 @@
#ifndef BLF_STANDALONE
# include "GPU_immediate.h"
# include "GPU_extensions.h"
#endif
#include "blf_internal_types.h"
@ -146,7 +147,7 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table));
memset(gc->bucket, 0, sizeof(gc->bucket));
gc->textures = (GLuint *)MEM_mallocN(sizeof(GLuint) * 256, __func__);
gc->textures = (GPUTexture **)MEM_callocN(sizeof(GPUTexture *) * 256, __func__);
gc->textures_len = 256;
gc->texture_current = BLF_TEXTURE_UNSET;
gc->offset_x = 3; /* enough padding for blur */
@ -196,16 +197,17 @@ void blf_glyph_cache_clear(FontBLF *font)
void blf_glyph_cache_free(GlyphCacheBLF *gc)
{
GlyphBLF *g;
int i;
unsigned int i;
for (i = 0; i < 257; i++) {
while ((g = BLI_pophead(&gc->bucket[i]))) {
blf_glyph_free(g);
}
}
if (gc->texture_current != BLF_TEXTURE_UNSET) {
glDeleteTextures((int)gc->texture_current + 1, gc->textures);
for (i = 0; i < gc->textures_len; i++) {
if (gc->textures[i]) {
GPU_texture_free(gc->textures[i]);
}
}
MEM_freeN(gc->textures);
MEM_freeN(gc);
@ -214,13 +216,14 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc)
static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
{
int i;
char error[256];
/* move the index. */
gc->texture_current++;
if (UNLIKELY(gc->texture_current >= gc->textures_len)) {
gc->textures_len *= 2;
gc->textures = MEM_reallocN((void *)gc->textures, sizeof(GLuint) * gc->textures_len);
gc->textures = MEM_recallocN((void *)gc->textures, sizeof(GPUTexture*) * gc->textures_len);
}
gc->p2_width = (int)blf_next_p2((unsigned int)((gc->glyphs_len_free * gc->glyph_width_max) + (gc->pad * 2)));
@ -235,16 +238,12 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
gc->p2_height = font->tex_size_max;
}
glGenTextures(1, &gc->textures[gc->texture_current]);
glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = gc->textures[gc->texture_current]));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
unsigned char *pixels = MEM_callocN((size_t)gc->p2_width * (size_t)gc->p2_height, "BLF texture init");
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, gc->p2_width, gc->p2_height, 0, GL_RED, GL_UNSIGNED_BYTE, pixels);
MEM_freeN(pixels);
GPUTexture *tex = GPU_texture_create_2D(gc->p2_width, gc->p2_height, GPU_R8, NULL, error);;
gc->textures[gc->texture_current] = tex;
GPU_texture_bind(tex, 0);
GPU_texture_wrap_mode(tex, false);
GPU_texture_filters(tex, GPU_NEAREST, GPU_LINEAR);
GPU_texture_unbind(tex);
}
GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
@ -437,13 +436,11 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
if ((!g->width) || (!g->height))
return;
glActiveTexture(GL_TEXTURE0);
if (g->build_tex == 0) {
GlyphCacheBLF *gc = font->glyph_cache;
if (font->tex_size_max == -1)
glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->tex_size_max);
font->tex_size_max = GPU_max_texture_size();
if (gc->texture_current == BLF_TEXTURE_UNSET) {
blf_glyph_cache_texture(font, gc);
@ -477,22 +474,7 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
BLI_assert(g->height > 0);
}
GLint lsb_first, row_length, alignment;
glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsb_first);
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, g->tex);
glTexSubImage2D(GL_TEXTURE_2D, 0, g->offset_x, g->offset_y, g->width, g->height, GL_RED, GL_UNSIGNED_BYTE, g->bitmap);
glPixelStorei(GL_UNPACK_LSB_FIRST, lsb_first);
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
GPU_texture_update_sub(g->tex, g->bitmap, g->offset_x, g->offset_y, 0, g->width, g->height, 0);
g->uv[0][0] = ((float)g->offset_x) / ((float)gc->p2_width);
g->uv[0][1] = ((float)g->offset_y) / ((float)gc->p2_height);
@ -520,7 +502,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
if (font->tex_bind_state != g->tex) {
blf_batch_draw();
glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = g->tex));
font->tex_bind_state = g->tex;
GPU_texture_bind(font->tex_bind_state, 0);
}
g_batch.tex_bind_state = g->tex;

View File

@ -32,6 +32,7 @@
#define __BLF_INTERNAL_TYPES_H__
#include "../../../intern/gawain/gawain/gwn_vertex_buffer.h"
#include "GPU_texture.h"
#define BLF_BATCH_DRAW_LEN_MAX 2048 /* in glyph */
@ -45,7 +46,7 @@ typedef struct BatchBLF {
float ofs[2]; /* copy of font->pos */
float mat[4][4]; /* previous call modelmatrix. */
bool enabled, active, simple_shader;
unsigned int tex_bind_state;
GPUTexture *tex_bind_state;
} BatchBLF;
extern BatchBLF g_batch;
@ -78,7 +79,7 @@ typedef struct GlyphCacheBLF {
struct GlyphBLF *glyph_ascii_table[256];
/* texture array, to draw the glyphs. */
unsigned int *textures;
GPUTexture **textures;
/* size of the array. */
unsigned int textures_len;
@ -133,7 +134,7 @@ typedef struct GlyphBLF {
int advance_i;
/* texture id where this glyph is store. */
unsigned int tex;
GPUTexture* tex;
/* position inside the texture where this glyph is store. */
int offset_x;
@ -244,7 +245,7 @@ typedef struct FontBLF {
int tex_size_max;
/* cache current OpenGL texture to save calls into the API */
unsigned int tex_bind_state;
GPUTexture *tex_bind_state;
/* font options. */
int flags;

View File

@ -142,6 +142,19 @@ typedef enum GPUTextureFormat {
GPU_DEPTH_COMPONENT16,
} GPUTextureFormat;
/* These map directly to the GL_ blend functions, to minimize API add as needed*/
typedef enum GPUBlendFunction {
GPU_ONE,
GPU_SRC_ALPHA,
GPU_ONE_MINUS_SRC_ALPHA
} GPUBlendFunction;
/* These map directly to the GL_ filter functions, to minimize API add as needed*/
typedef enum GPUFilterFunction {
GPU_NEAREST,
GPU_LINEAR
} GPUFilterFunction;
unsigned int GPU_texture_memory_usage_get(void);
GPUTexture *GPU_texture_create_1D(
@ -166,7 +179,8 @@ GPUTexture *GPU_texture_from_blender(
struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
void GPU_texture_update(GPUTexture *tex, const float *pixels);
void GPU_texture_update(GPUTexture *tex, const void *pixels);
void GPU_texture_update_sub(GPUTexture *tex, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth);
void GPU_invalid_tex_init(void);
void GPU_invalid_tex_bind(int mode);
@ -189,6 +203,7 @@ void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare);
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter);
void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter);
void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat);
void GPU_texture_filters(GPUTexture *tex, GPUFilterFunction min_filter, GPUFilterFunction mag_filter);
void GPU_texture_attach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment);
int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb);
@ -204,6 +219,10 @@ bool GPU_texture_stencil(const GPUTexture *tex);
bool GPU_texture_integer(const GPUTexture *tex);
int GPU_texture_opengl_bindcode(const GPUTexture *tex);
void GPU_blend(bool enable);
void GPU_blend_set_func_separate(GPUBlendFunction src_rgb, GPUBlendFunction dst_rgb, GPUBlendFunction src_alpha, GPUBlendFunction dst_alpha);
void GPU_blend_set_func(GPUBlendFunction sfactor, GPUBlendFunction dfactor);
#ifdef __cplusplus
}
#endif

View File

@ -171,6 +171,10 @@ static GLenum gpu_texture_get_format(
default: break;
}
}
else if (ELEM(data_type, GPU_R8)) {
*data_format = GL_UNSIGNED_BYTE;
*format = GL_RED;
}
else {
*data_format = GL_FLOAT;
*format_flag |= GPU_FORMAT_FLOAT;
@ -882,37 +886,52 @@ GPUTexture *GPU_texture_create_from_vertbuf(Gwn_VertBuf *vert)
return GPU_texture_create_buffer(data_type, vert->vbo_id);
}
void GPU_texture_update(GPUTexture *tex, const float *pixels)
void GPU_texture_update_sub(GPUTexture *tex, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth)
{
BLI_assert(tex->format > -1);
BLI_assert(tex->components > -1);
GLenum format, data_format;
GLint alignment;
gpu_texture_get_format(tex->components, tex->format, &format, &data_format,
&tex->format_flag, &tex->bytesize);
&tex->format_flag, &tex->bytesize);
/* The default pack size for textures is 4, which won't work for byte based textures */
if (tex->bytesize == 1) {
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
glBindTexture(tex->target, tex->bindcode);
switch (tex->target) {
case GL_TEXTURE_2D:
case GL_TEXTURE_2D_MULTISAMPLE:
case GL_TEXTURE_1D_ARRAY:
glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, data_format, pixels);
glTexSubImage2D(tex->target, 0, offset_x, offset_y, width, height, format, data_format, pixels);
break;
case GL_TEXTURE_1D:
glTexSubImage1D(tex->target, 0, 0, tex->w, format, data_format, pixels);
glTexSubImage1D(tex->target, 0, offset_x, width, format, data_format, pixels);
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->d, format, data_format, pixels);
glTexSubImage3D(tex->target, 0, offset_x, offset_y, offset_z, width, height, depth, format, data_format, pixels);
break;
default:
BLI_assert(!"tex->target mode not supported");
}
if (tex->bytesize == 1) {
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
}
glBindTexture(tex->target, 0);
}
void GPU_texture_update(GPUTexture *tex, const void *pixels)
{
GPU_texture_update_sub(tex, pixels, 0, 0, 0, tex->w, tex->h, tex->d);
}
void GPU_invalid_tex_init(void)
{
memory_usage = 0;
@ -1068,6 +1087,34 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat)
glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat);
}
static GLenum gpu_get_gl_filterfunction(GPUFilterFunction filter)
{
switch (filter)
{
case GPU_NEAREST:
return GL_NEAREST;
case GPU_LINEAR:
return GL_LINEAR;
default:
BLI_assert(!"Unhandled filter mode");
return GL_NEAREST;
}
}
void GPU_texture_filters(GPUTexture *tex, GPUFilterFunction min_filter, GPUFilterFunction mag_filter)
{
WARN_NOT_BOUND(tex);
/* Stencil and integer format does not support filtering. */
BLI_assert(!(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
BLI_assert(mag_filter == GPU_NEAREST || mag_filter == GPU_LINEAR);
glActiveTexture(GL_TEXTURE0 + tex->number);
glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, gpu_get_gl_filterfunction(min_filter));
glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, gpu_get_gl_filterfunction(mag_filter));
}
static void gpu_texture_delete(GPUTexture *tex)
{
if (tex->bindcode)
@ -1207,3 +1254,43 @@ int GPU_texture_detach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb)
BLI_assert(!"Error: Texture: Framebuffer is not attached");
return 0;
}
void GPU_blend(bool enable)
{
if (enable) {
glEnable(GL_BLEND);
}
else {
glDisable(GL_BLEND);
}
}
static GLenum gpu_get_gl_blendfunction(GPUBlendFunction blend)
{
switch (blend)
{
case GPU_ONE:
return GL_ONE;
case GPU_SRC_ALPHA:
return GL_SRC_ALPHA;
case GPU_ONE_MINUS_SRC_ALPHA:
return GL_ONE_MINUS_SRC_ALPHA;
default:
BLI_assert(!"Unhandled blend mode");
return GL_ZERO;
}
}
void GPU_blend_set_func_separate(GPUBlendFunction src_rgb, GPUBlendFunction dst_rgb, GPUBlendFunction src_alpha, GPUBlendFunction dst_alpha)
{
glBlendFuncSeparate(gpu_get_gl_blendfunction(src_rgb),
gpu_get_gl_blendfunction(dst_rgb),
gpu_get_gl_blendfunction(src_alpha),
gpu_get_gl_blendfunction(dst_alpha));
}
void GPU_blend_set_func(GPUBlendFunction sfactor, GPUBlendFunction dfactor)
{
glBlendFunc(gpu_get_gl_blendfunction(sfactor), gpu_get_gl_blendfunction(dfactor));
}