Cleanup: Split gpu_texture_image.c into BKE and IMB modules
This is in order to disolve GPU_draw.h into more meaningful code blocks. All the Image related function are in `image_gpu.c`. All the MovieClip related function are in `movieclip.c`. The IMB module now has a connection with GPU. This is not strickly necessary and the code could be move to `image_gpu.c` if needed. The Image garbage collection is also ported to `image_gpu.c`.
This commit is contained in:
parent
7e8d493730
commit
5f6fb5bb41
|
@ -55,6 +55,7 @@ void BKE_image_free_packedfiles(struct Image *image);
|
|||
void BKE_image_free_views(struct Image *image);
|
||||
void BKE_image_free_buffers(struct Image *image);
|
||||
void BKE_image_free_buffers_ex(struct Image *image, bool do_lock);
|
||||
void BKE_image_free_gputextures(struct Image *ima);
|
||||
/* call from library */
|
||||
void BKE_image_free(struct Image *image);
|
||||
|
||||
|
@ -274,6 +275,10 @@ void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
|
|||
/* does all images with type MOVIE or SEQUENCE */
|
||||
void BKE_image_all_free_anim_ibufs(struct Main *bmain, int except_frame);
|
||||
|
||||
void BKE_image_free_all_gputextures(struct Main *bmain);
|
||||
void BKE_image_free_anim_gputextures(struct Main *bmain);
|
||||
void BKE_image_free_old_gputextures(struct Main *bmain);
|
||||
|
||||
bool BKE_image_memorypack(struct Image *ima);
|
||||
void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath);
|
||||
void BKE_image_packfiles_from_mem(struct ReportList *reports,
|
||||
|
@ -362,6 +367,30 @@ bool BKE_image_has_loaded_ibuf(struct Image *image);
|
|||
struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name);
|
||||
struct ImBuf *BKE_image_get_first_ibuf(struct Image *image);
|
||||
|
||||
/* Not to be use directly. */
|
||||
struct GPUTexture *BKE_image_create_gpu_texture_from_ibuf(struct Image *image, struct ImBuf *ibuf);
|
||||
|
||||
/* Get the GPUTexture for a given `Image`.
|
||||
*
|
||||
* `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
|
||||
* available. It is also required when requesting the GPUTexture for a render result. */
|
||||
struct GPUTexture *BKE_image_get_gpu_texture(struct Image *image,
|
||||
struct ImageUser *iuser,
|
||||
struct ImBuf *ibuf);
|
||||
struct GPUTexture *BKE_image_get_gpu_tiles(struct Image *image,
|
||||
struct ImageUser *iuser,
|
||||
struct ImBuf *ibuf);
|
||||
struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image,
|
||||
struct ImageUser *iuser,
|
||||
struct ImBuf *ibuf);
|
||||
|
||||
void BKE_image_update_gputexture(
|
||||
struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
|
||||
void BKE_image_paint_set_mipmap(struct Main *bmain, bool mipmap);
|
||||
|
||||
/* Delayed free of OpenGL buffers by main thread */
|
||||
void BKE_image_free_unused_gpu_textures(void);
|
||||
|
||||
struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name);
|
||||
bool BKE_image_remove_renderslot(struct Image *ima, struct ImageUser *iuser, int slot);
|
||||
struct RenderSlot *BKE_image_get_renderslot(struct Image *ima, int slot);
|
||||
|
|
|
@ -113,6 +113,11 @@ bool BKE_movieclip_put_frame_if_possible(struct MovieClip *clip,
|
|||
struct MovieClipUser *user,
|
||||
struct ImBuf *ibuf);
|
||||
|
||||
struct GPUTexture *BKE_movieclip_get_gpu_texture(struct MovieClip *clip,
|
||||
struct MovieClipUser *cuser);
|
||||
|
||||
void BKE_movieclip_free_gputexture(struct MovieClip *clip);
|
||||
|
||||
/* Dependency graph evaluation. */
|
||||
|
||||
void BKE_movieclip_eval_update(struct Depsgraph *depsgraph,
|
||||
|
|
|
@ -134,6 +134,7 @@ set(SRC
|
|||
intern/idtype.c
|
||||
intern/image.c
|
||||
intern/image_gen.c
|
||||
intern/image_gpu.c
|
||||
intern/image_save.c
|
||||
intern/ipo.c
|
||||
intern/kelvinlet.c
|
||||
|
|
|
@ -90,7 +90,6 @@
|
|||
|
||||
#include "RE_pipeline.h"
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "BLI_sys_types.h" // for intptr_t support
|
||||
|
@ -393,7 +392,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
|
|||
ima->rr = NULL;
|
||||
}
|
||||
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
|
||||
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
|
||||
tile->ok = IMA_OK;
|
||||
|
|
|
@ -13,36 +13,24 @@
|
|||
* 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.
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*
|
||||
* Utility functions for dealing with OpenGL texture & material context,
|
||||
* mipmap generation and light objects.
|
||||
*
|
||||
* These are some obscure rendering functions shared between the game engine (not anymore)
|
||||
* and the blender, in this module to avoid duplication
|
||||
* and abstract them away from the rest a bit.
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_boxpack_2d.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_movieclip_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "IMB_colormanagement.h"
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
@ -50,218 +38,31 @@
|
|||
#include "BKE_global.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_movieclip.h"
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_state.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
static void gpu_free_image(Image *ima, const bool immediate);
|
||||
/* Prototypes. */
|
||||
static void gpu_free_unused_buffers(void);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utility functions
|
||||
* \{ */
|
||||
|
||||
/** Checking powers of two for images since OpenGL ES requires it */
|
||||
#ifdef WITH_DDS
|
||||
static bool is_power_of_2_resolution(int w, int h)
|
||||
{
|
||||
return is_power_of_2_i(w) && is_power_of_2_i(h);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool is_over_resolution_limit(int w, int h)
|
||||
{
|
||||
int size = GPU_max_texture_size();
|
||||
int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
|
||||
|
||||
return (w > reslimit || h > reslimit);
|
||||
}
|
||||
|
||||
static int smaller_power_of_2_limit(int num)
|
||||
{
|
||||
int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, GPU_max_texture_size()) :
|
||||
GPU_max_texture_size();
|
||||
/* take texture clamping into account */
|
||||
if (num > reslimit) {
|
||||
return reslimit;
|
||||
}
|
||||
|
||||
return power_of_2_min_i(num);
|
||||
}
|
||||
|
||||
static GPUTexture **gpu_get_image_gputexture(Image *ima,
|
||||
eGPUTextureTarget textarget,
|
||||
const int multiview_eye)
|
||||
{
|
||||
const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
|
||||
BLI_assert(in_range);
|
||||
|
||||
if (in_range) {
|
||||
return &(ima->gputexture[textarget][multiview_eye]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GPUTexture **gpu_get_movieclip_gputexture(MovieClip *clip,
|
||||
MovieClipUser *cuser,
|
||||
eGPUTextureTarget textarget)
|
||||
{
|
||||
LISTBASE_FOREACH (MovieClip_RuntimeGPUTexture *, tex, &clip->runtime.gputextures) {
|
||||
if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) {
|
||||
if (tex == NULL) {
|
||||
tex = (MovieClip_RuntimeGPUTexture *)MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture),
|
||||
__func__);
|
||||
|
||||
for (int i = 0; i < TEXTARGET_COUNT; i++) {
|
||||
tex->gputexture[i] = NULL;
|
||||
}
|
||||
|
||||
memcpy(&tex->user, cuser, sizeof(MovieClipUser));
|
||||
BLI_addtail(&clip->runtime.gputextures, tex);
|
||||
}
|
||||
|
||||
return &tex->gputexture[textarget];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply colormanagement and scale buffer if needed.
|
||||
* *r_freedata is set to true if the returned buffer need to be manually freed.
|
||||
**/
|
||||
static void *IMB_gpu_get_data(const ImBuf *ibuf,
|
||||
const bool do_rescale,
|
||||
const int rescale_size[2],
|
||||
const bool compress_as_srgb,
|
||||
const bool store_premultiplied,
|
||||
bool *r_freedata)
|
||||
{
|
||||
const bool is_float_rect = (ibuf->rect_float != NULL);
|
||||
void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect;
|
||||
|
||||
if (is_float_rect) {
|
||||
/* Float image is already in scene linear colorspace or non-color data by
|
||||
* convention, no colorspace conversion needed. But we do require 4 channels
|
||||
* currently. */
|
||||
if (ibuf->channels != 4 || !store_premultiplied) {
|
||||
data_rect = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
|
||||
*r_freedata = true;
|
||||
|
||||
if (data_rect == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IMB_colormanagement_imbuf_to_float_texture(
|
||||
(float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Byte image is in original colorspace from the file. If the file is sRGB
|
||||
* scene linear, or non-color data no conversion is needed. Otherwise we
|
||||
* compress as scene linear + sRGB transfer function to avoid precision loss
|
||||
* in common cases.
|
||||
*
|
||||
* We must also convert to premultiplied for correct texture interpolation
|
||||
* and consistency with float images. */
|
||||
if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
|
||||
data_rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
|
||||
*r_freedata = true;
|
||||
|
||||
if (data_rect == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Texture storage of images is defined by the alpha mode of the image. The
|
||||
* downside of this is that there can be artifacts near alpha edges. However,
|
||||
* this allows us to use sRGB texture formats and preserves color values in
|
||||
* zero alpha areas, and appears generally closer to what game engines that we
|
||||
* want to be compatible with do. */
|
||||
IMB_colormanagement_imbuf_to_byte_texture(
|
||||
(uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
|
||||
}
|
||||
}
|
||||
|
||||
if (do_rescale) {
|
||||
uint *rect = (is_float_rect) ? NULL : (uint *)data_rect;
|
||||
float *rect_float = (is_float_rect) ? (float *)data_rect : NULL;
|
||||
|
||||
ImBuf *scale_ibuf = IMB_allocFromBuffer(rect, rect_float, ibuf->x, ibuf->y, 4);
|
||||
IMB_scaleImBuf(scale_ibuf, UNPACK2(rescale_size));
|
||||
|
||||
data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect;
|
||||
*r_freedata = true;
|
||||
/* Steal the rescaled buffer to avoid double free. */
|
||||
scale_ibuf->rect_float = NULL;
|
||||
scale_ibuf->rect = NULL;
|
||||
IMB_freeImBuf(scale_ibuf);
|
||||
}
|
||||
return data_rect;
|
||||
}
|
||||
|
||||
static void IMB_gpu_get_format(const ImBuf *ibuf,
|
||||
bool high_bitdepth,
|
||||
eGPUDataFormat *r_data_format,
|
||||
eGPUTextureFormat *r_texture_format)
|
||||
{
|
||||
const bool float_rect = (ibuf->rect_float != NULL);
|
||||
const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
|
||||
!IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
|
||||
high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
|
||||
|
||||
*r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
|
||||
|
||||
if (float_rect) {
|
||||
*r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
|
||||
}
|
||||
else {
|
||||
*r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_DDS
|
||||
/* Return false if no suitable format was found. */
|
||||
static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format)
|
||||
{
|
||||
/* For DDS we only support data, scene linear and sRGB. Converting to
|
||||
* different colorspace would break the compression. */
|
||||
const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
|
||||
!IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
|
||||
|
||||
if (ibuf->dds_data.fourcc == FOURCC_DXT1) {
|
||||
*r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT1 : GPU_RGBA8_DXT1;
|
||||
}
|
||||
else if (ibuf->dds_data.fourcc == FOURCC_DXT3) {
|
||||
*r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT3 : GPU_RGBA8_DXT3;
|
||||
}
|
||||
else if (ibuf->dds_data.fourcc == FOURCC_DXT5) {
|
||||
*r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT5 : GPU_RGBA8_DXT5;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool mipmap_enabled(void)
|
||||
{
|
||||
/* This used to be a userpref option. Maybe it will be re-introduce late. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
static void image_free_gpu(Image *ima, const bool immediate);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name UDIM gpu texture
|
||||
* \{ */
|
||||
|
||||
static bool is_over_resolution_limit(int w, int h)
|
||||
{
|
||||
return (w > GPU_texture_size_with_limit(w) || h > GPU_texture_size_with_limit(h));
|
||||
}
|
||||
|
||||
static int smaller_power_of_2_limit(int num)
|
||||
{
|
||||
return power_of_2_min_i(GPU_texture_size_with_limit(num));
|
||||
}
|
||||
|
||||
static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
|
||||
{
|
||||
GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye];
|
||||
|
@ -421,7 +222,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
|
|||
BKE_image_release_ibuf(ima, ibuf, NULL);
|
||||
}
|
||||
|
||||
if (mipmap_enabled()) {
|
||||
if (GPU_mipmap_enabled()) {
|
||||
GPU_texture_generate_mipmap(tex);
|
||||
GPU_texture_mipmap_mode(tex, true, true);
|
||||
if (ima) {
|
||||
|
@ -443,76 +244,37 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
|
|||
/** \name Regular gpu texture
|
||||
* \{ */
|
||||
|
||||
static GPUTexture *IMB_create_gpu_texture(ImBuf *ibuf, bool use_high_bitdepth, bool use_premult)
|
||||
static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
|
||||
eGPUTextureTarget textarget,
|
||||
const int multiview_eye)
|
||||
{
|
||||
GPUTexture *tex = NULL;
|
||||
bool do_rescale = is_over_resolution_limit(ibuf->x, ibuf->y);
|
||||
const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
|
||||
BLI_assert(in_range);
|
||||
|
||||
#ifdef WITH_DDS
|
||||
if (ibuf->ftype == IMB_FTYPE_DDS) {
|
||||
eGPUTextureFormat compressed_format;
|
||||
if (!IMB_gpu_get_compressed_format(ibuf, &compressed_format)) {
|
||||
fprintf(stderr, "Unable to find a suitable DXT compression,");
|
||||
}
|
||||
else if (do_rescale) {
|
||||
fprintf(stderr, "Unable to load DXT image resolution,");
|
||||
}
|
||||
else if (!is_power_of_2_resolution(ibuf->x, ibuf->y)) {
|
||||
fprintf(stderr, "Unable to load non-power-of-two DXT image resolution,");
|
||||
}
|
||||
else {
|
||||
tex = GPU_texture_create_compressed(
|
||||
ibuf->x, ibuf->y, ibuf->dds_data.nummipmaps, compressed_format, ibuf->dds_data.data);
|
||||
|
||||
if (tex != NULL) {
|
||||
return tex;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "ST3C support not found,");
|
||||
}
|
||||
}
|
||||
/* Fallback to uncompressed texture. */
|
||||
fprintf(stderr, " falling back to uncompressed.\n");
|
||||
if (in_range) {
|
||||
return &(ima->gputexture[textarget][multiview_eye]);
|
||||
}
|
||||
#endif
|
||||
|
||||
eGPUDataFormat data_format;
|
||||
eGPUTextureFormat tex_format;
|
||||
IMB_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
|
||||
|
||||
int size[2] = {ibuf->x, ibuf->y};
|
||||
if (do_rescale) {
|
||||
size[0] = smaller_power_of_2_limit(size[0]);
|
||||
size[1] = smaller_power_of_2_limit(size[1]);
|
||||
}
|
||||
|
||||
const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
|
||||
bool freebuf = false;
|
||||
|
||||
void *data = IMB_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
|
||||
|
||||
/* Create Texture. */
|
||||
tex = GPU_texture_create_nD(UNPACK2(size), 0, 2, data, tex_format, data_format, 0, false, NULL);
|
||||
|
||||
GPU_texture_anisotropic_filter(tex, true);
|
||||
|
||||
if (freebuf) {
|
||||
MEM_SAFE_FREE(data);
|
||||
}
|
||||
|
||||
return tex;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the GPUTexture for a given `Image`.
|
||||
*
|
||||
* `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
|
||||
* available. It is also required when requesting the GPUTexture for a render result. */
|
||||
GPUTexture *GPU_texture_from_blender(Image *ima,
|
||||
ImageUser *iuser,
|
||||
ImBuf *ibuf,
|
||||
eGPUTextureTarget textarget)
|
||||
static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
|
||||
{
|
||||
switch (textarget) {
|
||||
case TEXTARGET_2D_ARRAY:
|
||||
return GPU_texture_create_error(2, true);
|
||||
case TEXTARGET_TILE_MAPPING:
|
||||
return GPU_texture_create_error(1, true);
|
||||
case TEXTARGET_2D:
|
||||
default:
|
||||
return GPU_texture_create_error(2, false);
|
||||
}
|
||||
}
|
||||
|
||||
static GPUTexture *image_get_gpu_texture(Image *ima,
|
||||
ImageUser *iuser,
|
||||
ImBuf *ibuf,
|
||||
eGPUTextureTarget textarget)
|
||||
{
|
||||
#ifndef GPU_STANDALONE
|
||||
if (ima == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -523,7 +285,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima,
|
|||
|
||||
/* currently, gpu refresh tagging is used by ima sequences */
|
||||
if (ima->gpuflag & IMA_GPU_REFRESH) {
|
||||
gpu_free_image(ima, true);
|
||||
image_free_gpu(ima, true);
|
||||
ima->gpuflag &= ~IMA_GPU_REFRESH;
|
||||
}
|
||||
|
||||
|
@ -531,7 +293,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima,
|
|||
BKE_image_tag_time(ima);
|
||||
|
||||
/* Test if we already have a texture. */
|
||||
GPUTexture **tex = gpu_get_image_gputexture(ima, textarget, iuser ? iuser->multiview_eye : 0);
|
||||
GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, iuser ? iuser->multiview_eye : 0);
|
||||
if (*tex) {
|
||||
return *tex;
|
||||
}
|
||||
|
@ -540,7 +302,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima,
|
|||
* texture with zero bindcode so we don't keep trying. */
|
||||
ImageTile *tile = BKE_image_get_tile(ima, 0);
|
||||
if (tile == NULL || tile->ok == 0) {
|
||||
*tex = GPU_texture_create_error(textarget);
|
||||
*tex = image_gpu_texture_error_create(textarget);
|
||||
return *tex;
|
||||
}
|
||||
|
||||
|
@ -549,7 +311,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima,
|
|||
if (ibuf_intern == NULL) {
|
||||
ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
|
||||
if (ibuf_intern == NULL) {
|
||||
*tex = GPU_texture_create_error(textarget);
|
||||
*tex = image_gpu_texture_error_create(textarget);
|
||||
return *tex;
|
||||
}
|
||||
}
|
||||
|
@ -568,7 +330,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima,
|
|||
|
||||
*tex = IMB_create_gpu_texture(ibuf_intern, use_high_bitdepth, store_premultiplied);
|
||||
|
||||
if (mipmap_enabled()) {
|
||||
if (GPU_mipmap_enabled()) {
|
||||
GPU_texture_bind(*tex, 0);
|
||||
GPU_texture_generate_mipmap(*tex);
|
||||
GPU_texture_unbind(*tex);
|
||||
|
@ -590,45 +352,150 @@ GPUTexture *GPU_texture_from_blender(Image *ima,
|
|||
GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
|
||||
|
||||
return *tex;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser)
|
||||
GPUTexture *BKE_image_get_gpu_texture(Image *image, ImageUser *iuser, ImBuf *ibuf)
|
||||
{
|
||||
#ifndef GPU_STANDALONE
|
||||
if (clip == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPUTexture **tex = gpu_get_movieclip_gputexture(clip, cuser, TEXTARGET_2D);
|
||||
if (*tex) {
|
||||
return *tex;
|
||||
}
|
||||
|
||||
/* check if we have a valid image buffer */
|
||||
ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser);
|
||||
if (ibuf == NULL) {
|
||||
*tex = GPU_texture_create_error(TEXTARGET_2D);
|
||||
return *tex;
|
||||
}
|
||||
|
||||
/* This only means RGBA16F instead of RGBA32F. */
|
||||
const bool high_bitdepth = false;
|
||||
const bool store_premultiplied = ibuf->rect_float ? false : true;
|
||||
*tex = IMB_create_gpu_texture(ibuf, high_bitdepth, store_premultiplied);
|
||||
|
||||
/* Do not generate mips for movieclips... too slow. */
|
||||
GPU_texture_mipmap_mode(*tex, false, true);
|
||||
|
||||
IMB_freeImBuf(ibuf);
|
||||
|
||||
return *tex;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_2D);
|
||||
}
|
||||
|
||||
GPUTexture *BKE_image_get_gpu_tiles(Image *image, ImageUser *iuser, ImBuf *ibuf)
|
||||
{
|
||||
return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_2D_ARRAY);
|
||||
}
|
||||
|
||||
GPUTexture *BKE_image_get_gpu_tilemap(Image *image, ImageUser *iuser, ImBuf *ibuf)
|
||||
{
|
||||
return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_TILE_MAPPING);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Delayed GPU texture free
|
||||
*
|
||||
* Image datablocks can be deleted by any thread, but there may not be any active OpenGL context.
|
||||
* In that case we push them into a queue and free the buffers later.
|
||||
* \{ */
|
||||
|
||||
static LinkNode *gpu_texture_free_queue = NULL;
|
||||
static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
|
||||
|
||||
static void gpu_free_unused_buffers(void)
|
||||
{
|
||||
if (gpu_texture_free_queue == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_mutex_lock(&gpu_texture_queue_mutex);
|
||||
|
||||
if (gpu_texture_free_queue != NULL) {
|
||||
GPUTexture *tex;
|
||||
while ((tex = (GPUTexture *)BLI_linklist_pop(&gpu_texture_free_queue))) {
|
||||
GPU_texture_free(tex);
|
||||
}
|
||||
gpu_texture_free_queue = NULL;
|
||||
}
|
||||
|
||||
BLI_mutex_unlock(&gpu_texture_queue_mutex);
|
||||
}
|
||||
|
||||
void BKE_image_free_unused_gpu_textures()
|
||||
{
|
||||
if (BLI_thread_is_main()) {
|
||||
gpu_free_unused_buffers();
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deletion
|
||||
* \{ */
|
||||
|
||||
static void image_free_gpu(Image *ima, const bool immediate)
|
||||
{
|
||||
for (int eye = 0; eye < 2; eye++) {
|
||||
for (int i = 0; i < TEXTARGET_COUNT; i++) {
|
||||
if (ima->gputexture[i][eye] != NULL) {
|
||||
if (immediate) {
|
||||
GPU_texture_free(ima->gputexture[i][eye]);
|
||||
}
|
||||
else {
|
||||
BLI_mutex_lock(&gpu_texture_queue_mutex);
|
||||
BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]);
|
||||
BLI_mutex_unlock(&gpu_texture_queue_mutex);
|
||||
}
|
||||
|
||||
ima->gputexture[i][eye] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
|
||||
}
|
||||
|
||||
void BKE_image_free_gputextures(Image *ima)
|
||||
{
|
||||
image_free_gpu(ima, BLI_thread_is_main());
|
||||
}
|
||||
|
||||
void BKE_image_free_all_gputextures(Main *bmain)
|
||||
{
|
||||
if (bmain) {
|
||||
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
|
||||
BKE_image_free_gputextures(ima);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* same as above but only free animated images */
|
||||
void BKE_image_free_anim_gputextures(Main *bmain)
|
||||
{
|
||||
if (bmain) {
|
||||
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
|
||||
if (BKE_image_is_animated(ima)) {
|
||||
BKE_image_free_gputextures(ima);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_image_free_old_gputextures(Main *bmain)
|
||||
{
|
||||
static int lasttime = 0;
|
||||
int ctime = (int)PIL_check_seconds_timer();
|
||||
|
||||
/*
|
||||
* Run garbage collector once for every collecting period of time
|
||||
* if textimeout is 0, that's the option to NOT run the collector
|
||||
*/
|
||||
if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* of course not! */
|
||||
if (G.is_rendering) {
|
||||
return;
|
||||
}
|
||||
|
||||
lasttime = ctime;
|
||||
|
||||
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
|
||||
if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
|
||||
/* If it's in GL memory, deallocate and set time tag to current time
|
||||
* This gives textures a "second chance" to be used before dying. */
|
||||
if (BKE_image_has_opengl_texture(ima)) {
|
||||
BKE_image_free_gputextures(ima);
|
||||
ima->lastused = ctime;
|
||||
}
|
||||
/* Otherwise, just kill the buffers */
|
||||
else {
|
||||
BKE_image_free_buffers(ima);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -745,10 +612,6 @@ static void gpu_texture_update_unscaled(GPUTexture *tex,
|
|||
static void gpu_texture_update_from_ibuf(
|
||||
GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
|
||||
{
|
||||
/* Partial update of texture for texture painting. This is often much
|
||||
* quicker than fully updating the texture for high resolution images. */
|
||||
GPU_texture_bind(tex, 0);
|
||||
|
||||
bool scaled;
|
||||
if (tile != NULL) {
|
||||
int *tilesize = tile->runtime.tilearray_size;
|
||||
|
@ -814,6 +677,8 @@ static void gpu_texture_update_from_ibuf(
|
|||
}
|
||||
}
|
||||
|
||||
GPU_texture_bind(tex, 0);
|
||||
|
||||
if (scaled) {
|
||||
/* Slower update where we first have to scale the input pixels. */
|
||||
if (tile != NULL) {
|
||||
|
@ -850,7 +715,7 @@ static void gpu_texture_update_from_ibuf(
|
|||
MEM_freeN(rect_float);
|
||||
}
|
||||
|
||||
if (mipmap_enabled()) {
|
||||
if (GPU_mipmap_enabled()) {
|
||||
GPU_texture_generate_mipmap(tex);
|
||||
}
|
||||
else {
|
||||
|
@ -860,7 +725,9 @@ static void gpu_texture_update_from_ibuf(
|
|||
GPU_texture_unbind(tex);
|
||||
}
|
||||
|
||||
void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
|
||||
/* Partial update of texture for texture painting. This is often much
|
||||
* quicker than fully updating the texture for high resolution images. */
|
||||
void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
|
||||
{
|
||||
#ifndef GPU_STANDALONE
|
||||
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
|
||||
|
@ -868,7 +735,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
|
|||
|
||||
if ((ibuf == NULL) || (w == 0) || (h == 0)) {
|
||||
/* Full reload of texture. */
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
}
|
||||
|
||||
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
|
||||
|
@ -891,9 +758,8 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
|
|||
* temporary disabling/enabling mipmapping on all images for quick texture
|
||||
* updates with glTexSubImage2D. images that didn't change don't have to be
|
||||
* re-uploaded to OpenGL */
|
||||
void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
|
||||
void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
|
||||
{
|
||||
#ifndef GPU_STANDALONE
|
||||
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
|
||||
if (BKE_image_has_opengl_texture(ima)) {
|
||||
if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
|
||||
|
@ -909,163 +775,13 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
|
|||
}
|
||||
}
|
||||
else {
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
|
||||
}
|
||||
}
|
||||
#endif /* GPU_STANDALONE */
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Delayed GPU texture free
|
||||
*
|
||||
* Image datablocks can be deleted by any thread, but there may not be any active OpenGL context.
|
||||
* In that case we push them into a queue and free the buffers later.
|
||||
* \{ */
|
||||
|
||||
static LinkNode *gpu_texture_free_queue = NULL;
|
||||
static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
|
||||
|
||||
static void gpu_free_unused_buffers()
|
||||
{
|
||||
if (gpu_texture_free_queue == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_mutex_lock(&gpu_texture_queue_mutex);
|
||||
|
||||
if (gpu_texture_free_queue != NULL) {
|
||||
GPUTexture *tex;
|
||||
while ((tex = (GPUTexture *)BLI_linklist_pop(&gpu_texture_free_queue))) {
|
||||
GPU_texture_free(tex);
|
||||
}
|
||||
gpu_texture_free_queue = NULL;
|
||||
}
|
||||
|
||||
BLI_mutex_unlock(&gpu_texture_queue_mutex);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deletion
|
||||
* \{ */
|
||||
|
||||
static void gpu_free_image(Image *ima, const bool immediate)
|
||||
{
|
||||
for (int eye = 0; eye < 2; eye++) {
|
||||
for (int i = 0; i < TEXTARGET_COUNT; i++) {
|
||||
if (ima->gputexture[i][eye] != NULL) {
|
||||
if (immediate) {
|
||||
GPU_texture_free(ima->gputexture[i][eye]);
|
||||
}
|
||||
else {
|
||||
BLI_mutex_lock(&gpu_texture_queue_mutex);
|
||||
BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]);
|
||||
BLI_mutex_unlock(&gpu_texture_queue_mutex);
|
||||
}
|
||||
|
||||
ima->gputexture[i][eye] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
|
||||
}
|
||||
|
||||
void GPU_free_unused_buffers()
|
||||
{
|
||||
if (BLI_thread_is_main()) {
|
||||
gpu_free_unused_buffers();
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_free_image(Image *ima)
|
||||
{
|
||||
gpu_free_image(ima, BLI_thread_is_main());
|
||||
}
|
||||
|
||||
void GPU_free_movieclip(struct MovieClip *clip)
|
||||
{
|
||||
/* number of gpu textures to keep around as cache
|
||||
* We don't want to keep too many GPU textures for
|
||||
* movie clips around, as they can be large.*/
|
||||
const int MOVIECLIP_NUM_GPUTEXTURES = 1;
|
||||
|
||||
while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) {
|
||||
MovieClip_RuntimeGPUTexture *tex = (MovieClip_RuntimeGPUTexture *)BLI_pophead(
|
||||
&clip->runtime.gputextures);
|
||||
for (int i = 0; i < TEXTARGET_COUNT; i++) {
|
||||
/* free glsl image binding */
|
||||
if (tex->gputexture[i]) {
|
||||
GPU_texture_free(tex->gputexture[i]);
|
||||
tex->gputexture[i] = NULL;
|
||||
}
|
||||
}
|
||||
MEM_freeN(tex);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_free_images(Main *bmain)
|
||||
{
|
||||
if (bmain) {
|
||||
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
|
||||
GPU_free_image(ima);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* same as above but only free animated images */
|
||||
void GPU_free_images_anim(Main *bmain)
|
||||
{
|
||||
if (bmain) {
|
||||
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
|
||||
if (BKE_image_is_animated(ima)) {
|
||||
GPU_free_image(ima);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_free_images_old(Main *bmain)
|
||||
{
|
||||
static int lasttime = 0;
|
||||
int ctime = (int)PIL_check_seconds_timer();
|
||||
|
||||
/*
|
||||
* Run garbage collector once for every collecting period of time
|
||||
* if textimeout is 0, that's the option to NOT run the collector
|
||||
*/
|
||||
if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* of course not! */
|
||||
if (G.is_rendering) {
|
||||
return;
|
||||
}
|
||||
|
||||
lasttime = ctime;
|
||||
|
||||
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
|
||||
if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
|
||||
/* If it's in GL memory, deallocate and set time tag to current time
|
||||
* This gives textures a "second chance" to be used before dying. */
|
||||
if (BKE_image_has_opengl_texture(ima)) {
|
||||
GPU_free_image(ima);
|
||||
ima->lastused = ctime;
|
||||
}
|
||||
/* Otherwise, just kill the buffers */
|
||||
else {
|
||||
BKE_image_free_buffers(ima);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
|
@ -1867,3 +1867,84 @@ void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip
|
|||
DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
|
||||
movieclip_selection_sync(clip, (MovieClip *)clip->id.orig_id);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name GPU textures
|
||||
* \{ */
|
||||
|
||||
static GPUTexture **movieclip_get_gputexture_ptr(MovieClip *clip,
|
||||
MovieClipUser *cuser,
|
||||
eGPUTextureTarget textarget)
|
||||
{
|
||||
LISTBASE_FOREACH (MovieClip_RuntimeGPUTexture *, tex, &clip->runtime.gputextures) {
|
||||
if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) {
|
||||
if (tex == NULL) {
|
||||
tex = (MovieClip_RuntimeGPUTexture *)MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture),
|
||||
__func__);
|
||||
|
||||
for (int i = 0; i < TEXTARGET_COUNT; i++) {
|
||||
tex->gputexture[i] = NULL;
|
||||
}
|
||||
|
||||
memcpy(&tex->user, cuser, sizeof(MovieClipUser));
|
||||
BLI_addtail(&clip->runtime.gputextures, tex);
|
||||
}
|
||||
|
||||
return &tex->gputexture[textarget];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPUTexture *BKE_movieclip_get_gpu_texture(MovieClip *clip, MovieClipUser *cuser)
|
||||
{
|
||||
if (clip == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPUTexture **tex = movieclip_get_gputexture_ptr(clip, cuser, TEXTARGET_2D);
|
||||
if (*tex) {
|
||||
return *tex;
|
||||
}
|
||||
|
||||
/* check if we have a valid image buffer */
|
||||
ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser);
|
||||
if (ibuf == NULL) {
|
||||
*tex = GPU_texture_create_error(2, false);
|
||||
return *tex;
|
||||
}
|
||||
|
||||
/* This only means RGBA16F instead of RGBA32F. */
|
||||
const bool high_bitdepth = false;
|
||||
const bool store_premultiplied = ibuf->rect_float ? false : true;
|
||||
*tex = IMB_create_gpu_texture(ibuf, high_bitdepth, store_premultiplied);
|
||||
|
||||
/* Do not generate mips for movieclips... too slow. */
|
||||
GPU_texture_mipmap_mode(*tex, false, true);
|
||||
|
||||
IMB_freeImBuf(ibuf);
|
||||
|
||||
return *tex;
|
||||
}
|
||||
|
||||
void BKE_movieclip_free_gputexture(struct MovieClip *clip)
|
||||
{
|
||||
/* number of gpu textures to keep around as cache
|
||||
* We don't want to keep too many GPU textures for
|
||||
* movie clips around, as they can be large.*/
|
||||
const int MOVIECLIP_NUM_GPUTEXTURES = 1;
|
||||
|
||||
while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) {
|
||||
MovieClip_RuntimeGPUTexture *tex = (MovieClip_RuntimeGPUTexture *)BLI_pophead(
|
||||
&clip->runtime.gputextures);
|
||||
for (int i = 0; i < TEXTARGET_COUNT; i++) {
|
||||
/* free glsl image binding */
|
||||
if (tex->gputexture[i]) {
|
||||
GPU_texture_free(tex->gputexture[i]);
|
||||
tex->gputexture[i] = NULL;
|
||||
}
|
||||
}
|
||||
MEM_freeN(tex);
|
||||
}
|
||||
}
|
||||
/** \} */
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "IMB_imbuf.h"
|
||||
|
||||
#include "eevee_private.h"
|
||||
|
||||
#include "eevee_engine.h" /* own include */
|
||||
|
|
|
@ -63,7 +63,7 @@ static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_
|
|||
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
|
||||
|
||||
if (ibuf != NULL && ibuf->rect != NULL) {
|
||||
gpu_tex = GPU_texture_from_blender(image, &iuser, ibuf, TEXTARGET_2D);
|
||||
gpu_tex = BKE_image_get_gpu_texture(image, &iuser, ibuf);
|
||||
*r_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
|
||||
}
|
||||
BKE_image_release_ibuf(image, ibuf, lock);
|
||||
|
|
|
@ -175,7 +175,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
|
|||
}
|
||||
width = ibuf->x;
|
||||
height = ibuf->y;
|
||||
tex = GPU_texture_from_blender(image, iuser, ibuf, TEXTARGET_2D);
|
||||
tex = BKE_image_get_gpu_texture(image, iuser, ibuf);
|
||||
BKE_image_release_ibuf(image, ibuf, lock);
|
||||
iuser->scene = NULL;
|
||||
|
||||
|
@ -203,7 +203,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
|
|||
}
|
||||
|
||||
BKE_movieclip_user_set_frame(&bgpic->cuser, ctime);
|
||||
tex = GPU_texture_from_movieclip(clip, &bgpic->cuser);
|
||||
tex = BKE_movieclip_get_gpu_texture(clip, &bgpic->cuser);
|
||||
if (tex == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ static void OVERLAY_image_free_movieclips_textures(OVERLAY_Data *data)
|
|||
LinkData *link;
|
||||
while ((link = BLI_pophead(&data->stl->pd->bg_movie_clips))) {
|
||||
MovieClip *clip = (MovieClip *)link->data;
|
||||
GPU_free_movieclip(clip);
|
||||
BKE_movieclip_free_gputexture(clip);
|
||||
MEM_freeN(link);
|
||||
}
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
|||
if (ima != NULL) {
|
||||
ImageUser iuser = *ob->iuser;
|
||||
camera_background_images_stereo_setup(draw_ctx->scene, draw_ctx->v3d, ima, &iuser);
|
||||
tex = GPU_texture_from_blender(ima, &iuser, NULL, TEXTARGET_2D);
|
||||
tex = BKE_image_get_gpu_texture(ima, &iuser, NULL);
|
||||
if (tex) {
|
||||
size[0] = GPU_texture_orig_width(tex);
|
||||
size[1] = GPU_texture_orig_height(tex);
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "BKE_image.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
@ -136,7 +138,7 @@ void OVERLAY_paint_cache_init(OVERLAY_Data *vedata)
|
|||
state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
|
||||
DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
|
||||
|
||||
GPUTexture *tex = GPU_texture_from_blender(imapaint->stencil, NULL, NULL, TEXTARGET_2D);
|
||||
GPUTexture *tex = BKE_image_get_gpu_texture(imapaint->stencil, NULL, NULL);
|
||||
|
||||
const bool mask_premult = (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL);
|
||||
const bool mask_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0;
|
||||
|
|
|
@ -262,11 +262,11 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
|
|||
|
||||
if (ima) {
|
||||
if (ima->source == IMA_SRC_TILED) {
|
||||
tex = GPU_texture_from_blender(ima, iuser, NULL, TEXTARGET_2D_ARRAY);
|
||||
tex_tile_data = GPU_texture_from_blender(ima, iuser, NULL, TEXTARGET_TILE_MAPPING);
|
||||
tex = BKE_image_get_gpu_tiles(ima, iuser, NULL);
|
||||
tex_tile_data = BKE_image_get_gpu_tilemap(ima, iuser, NULL);
|
||||
}
|
||||
else {
|
||||
tex = GPU_texture_from_blender(ima, iuser, NULL, TEXTARGET_2D);
|
||||
tex = BKE_image_get_gpu_texture(ima, iuser, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1293,13 +1293,10 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass
|
|||
}
|
||||
|
||||
static void drw_shgroup_material_texture(DRWShadingGroup *grp,
|
||||
GPUMaterialTexture *tex,
|
||||
GPUTexture *gputex,
|
||||
const char *name,
|
||||
eGPUSamplerState state,
|
||||
eGPUTextureTarget textarget)
|
||||
eGPUSamplerState state)
|
||||
{
|
||||
GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget);
|
||||
|
||||
DRW_shgroup_uniform_texture_ex(grp, name, gputex, state);
|
||||
|
||||
GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images);
|
||||
|
@ -1315,15 +1312,16 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial
|
|||
LISTBASE_FOREACH (GPUMaterialTexture *, tex, &textures) {
|
||||
if (tex->ima) {
|
||||
/* Image */
|
||||
GPUTexture *gputex;
|
||||
if (tex->tiled_mapping_name[0]) {
|
||||
drw_shgroup_material_texture(
|
||||
grp, tex, tex->sampler_name, tex->sampler_state, TEXTARGET_2D_ARRAY);
|
||||
drw_shgroup_material_texture(
|
||||
grp, tex, tex->tiled_mapping_name, tex->sampler_state, TEXTARGET_TILE_MAPPING);
|
||||
gputex = BKE_image_get_gpu_tiles(tex->ima, tex->iuser, NULL);
|
||||
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
|
||||
gputex = BKE_image_get_gpu_tilemap(tex->ima, tex->iuser, NULL);
|
||||
drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state);
|
||||
}
|
||||
else {
|
||||
drw_shgroup_material_texture(
|
||||
grp, tex, tex->sampler_name, tex->sampler_state, TEXTARGET_2D);
|
||||
gputex = BKE_image_get_gpu_texture(tex->ima, tex->iuser, NULL);
|
||||
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
|
||||
}
|
||||
}
|
||||
else if (tex->colorband) {
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
#include "GPU_draw.h" /* GPU_free_image */
|
||||
#include "GPU_draw.h" /* BKE_image_free_gputextures */
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
@ -530,7 +530,7 @@ static void multiresbake_freejob(void *bkv)
|
|||
/* delete here, since this delete will be called from main thread */
|
||||
for (link = data->images.first; link; link = link->next) {
|
||||
Image *ima = (Image *)link->data;
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
}
|
||||
|
||||
MEM_freeN(data->ob_image.array);
|
||||
|
|
|
@ -308,7 +308,7 @@ static void refresh_images(BakeImages *bake_images)
|
|||
Image *ima = bake_images->data[i].image;
|
||||
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
|
||||
if (tile->ok == IMA_OK_LOADED) {
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
DEG_id_tag_update(&ima->id, 0);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ void imapaint_image_update(
|
|||
int h = imapaintpartial.y2 - imapaintpartial.y1;
|
||||
if (w && h) {
|
||||
/* Testing with partial update in uv editor too */
|
||||
GPU_paint_update_image(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
|
||||
BKE_image_update_gputexture(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1164,9 +1164,9 @@ void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob
|
|||
BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
|
||||
|
||||
if (U.glreslimit != 0) {
|
||||
GPU_free_images(bmain);
|
||||
BKE_image_free_all_gputextures(bmain);
|
||||
}
|
||||
GPU_paint_set_mipmap(bmain, 0);
|
||||
BKE_image_paint_set_mipmap(bmain, 0);
|
||||
|
||||
toggle_paint_cursor(scene, true);
|
||||
|
||||
|
@ -1189,9 +1189,9 @@ void ED_object_texture_paint_mode_exit_ex(Main *bmain, Scene *scene, Object *ob)
|
|||
ob->mode &= ~OB_MODE_TEXTURE_PAINT;
|
||||
|
||||
if (U.glreslimit != 0) {
|
||||
GPU_free_images(bmain);
|
||||
BKE_image_free_all_gputextures(bmain);
|
||||
}
|
||||
GPU_paint_set_mipmap(bmain, 1);
|
||||
BKE_image_paint_set_mipmap(bmain, 1);
|
||||
toggle_paint_cursor(scene, false);
|
||||
|
||||
Mesh *me = BKE_mesh_from_object(ob);
|
||||
|
|
|
@ -1784,7 +1784,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final)
|
|||
|
||||
if (final) {
|
||||
if (s->image && !(s->sima && s->sima->lock)) {
|
||||
GPU_free_image(s->image);
|
||||
BKE_image_free_gputextures(s->image);
|
||||
}
|
||||
|
||||
/* compositor listener deals with updating */
|
||||
|
|
|
@ -6134,7 +6134,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
|
|||
project_image_refresh_tagged(&ps);
|
||||
|
||||
for (a = 0; a < ps.image_tot; a++) {
|
||||
GPU_free_image(ps.projImages[a].ima);
|
||||
BKE_image_free_gputextures(ps.projImages[a].ima);
|
||||
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima);
|
||||
}
|
||||
|
||||
|
|
|
@ -2769,7 +2769,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
|
|||
ED_image_undo_push_end();
|
||||
|
||||
/* force GPU reupload, all image is invalid */
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
|
||||
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
|
||||
|
||||
|
@ -2860,7 +2860,7 @@ static int image_scale_exec(bContext *C, wmOperator *op)
|
|||
ED_image_undo_push_end();
|
||||
|
||||
/* force GPU reupload, all image is invalid */
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
|
||||
DEG_id_tag_update(&ima->id, 0);
|
||||
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
|
||||
|
|
|
@ -295,7 +295,8 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
|
|||
SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
|
||||
}
|
||||
|
||||
GPU_free_image(image); /* force OpenGL reload (maybe partial update will operate better?) */
|
||||
BKE_image_free_gputextures(
|
||||
image); /* force OpenGL reload (maybe partial update will operate better?) */
|
||||
if (ibuf->rect_float) {
|
||||
ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
|
||||
}
|
||||
|
@ -570,7 +571,7 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
|
|||
|
||||
if (changed) {
|
||||
BKE_image_mark_dirty(image, ibuf);
|
||||
GPU_free_image(image); /* force OpenGL reload */
|
||||
BKE_image_free_gputextures(image); /* force OpenGL reload */
|
||||
|
||||
if (ibuf->rect_float) {
|
||||
ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "BKE_context.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_key.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_main.h"
|
||||
|
@ -1617,7 +1618,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region)
|
|||
view3d_draw_view(C, region);
|
||||
|
||||
DRW_cache_free_old_batches(bmain);
|
||||
GPU_free_images_old(bmain);
|
||||
BKE_image_free_old_gputextures(bmain);
|
||||
GPU_pass_cache_garbage_collect();
|
||||
|
||||
/* XXX This is in order to draw UI batches with the DRW
|
||||
|
@ -1707,7 +1708,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
|
|||
{
|
||||
/* free images which can have changed on frame-change
|
||||
* warning! can be slow so only free animated images - campbell */
|
||||
GPU_free_images_anim(G.main); /* XXX :((( */
|
||||
BKE_image_free_anim_gputextures(G.main); /* XXX :((( */
|
||||
}
|
||||
|
||||
GPU_matrix_push_projection();
|
||||
|
|
|
@ -80,7 +80,6 @@ set(SRC
|
|||
intern/gpu_shader_interface.c
|
||||
intern/gpu_state.cc
|
||||
intern/gpu_texture.cc
|
||||
intern/gpu_texture_image.c
|
||||
intern/gpu_texture_fluid.c
|
||||
intern/gpu_uniformbuffer.cc
|
||||
intern/gpu_vertex_buffer.cc
|
||||
|
|
|
@ -26,29 +26,11 @@
|
|||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_object_enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct FluidModifierData;
|
||||
struct GPUTexture;
|
||||
struct Image;
|
||||
struct ImageUser;
|
||||
struct ImBuf;
|
||||
struct Main;
|
||||
struct MovieClip;
|
||||
struct MovieClipUser;
|
||||
|
||||
/* Texture creation from blender datablocks. */
|
||||
struct GPUTexture *GPU_texture_from_blender(struct Image *ima,
|
||||
struct ImageUser *iuser,
|
||||
struct ImBuf *ibuf,
|
||||
eGPUTextureTarget target);
|
||||
|
||||
struct GPUTexture *GPU_texture_from_movieclip(struct MovieClip *clip, struct MovieClipUser *cuser);
|
||||
|
||||
/* Fluid simulation. */
|
||||
void GPU_create_smoke(struct FluidModifierData *fmd, int highres);
|
||||
|
@ -56,25 +38,9 @@ void GPU_create_smoke_coba_field(struct FluidModifierData *fmd);
|
|||
void GPU_create_smoke_velocity(struct FluidModifierData *fmd);
|
||||
|
||||
/* Image updates and free. */
|
||||
void GPU_free_image(struct Image *ima);
|
||||
void GPU_free_movieclip(struct MovieClip *clip);
|
||||
void GPU_free_smoke(struct FluidModifierData *fmd);
|
||||
void GPU_free_smoke_velocity(struct FluidModifierData *fmd);
|
||||
|
||||
void GPU_free_images(struct Main *bmain);
|
||||
void GPU_free_images_anim(struct Main *bmain);
|
||||
void GPU_free_images_old(struct Main *bmain);
|
||||
|
||||
void GPU_paint_update_image(
|
||||
struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
|
||||
void GPU_paint_set_mipmap(struct Main *bmain, bool mipmap);
|
||||
|
||||
/* Delayed free of OpenGL buffers by main thread */
|
||||
void GPU_free_unused_buffers(void);
|
||||
|
||||
/* For internal use. */
|
||||
struct GPUTexture *GPU_texture_create_error(eGPUTextureTarget target);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -52,6 +52,8 @@ bool GPU_context_local_shaders_workaround(void);
|
|||
bool GPU_texture_copy_workaround(void);
|
||||
bool GPU_crappy_amd_driver(void);
|
||||
|
||||
int GPU_texture_size_with_limit(int res);
|
||||
|
||||
bool GPU_mem_stats_supported(void);
|
||||
void GPU_mem_stats_get(int *totalmem, int *freemem);
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ bool GPU_depth_mask_get(void);
|
|||
void GPU_stencil_mask(uint stencil);
|
||||
void GPU_unpack_row_length_set(uint len);
|
||||
void GPU_clip_distances(int enabled_len);
|
||||
bool GPU_mipmap_enabled(void);
|
||||
|
||||
void GPU_flush(void);
|
||||
void GPU_finish(void);
|
||||
|
|
|
@ -233,6 +233,8 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint bu
|
|||
GPUTexture *GPU_texture_create_compressed(
|
||||
int w, int h, int miplen, eGPUTextureFormat format, const void *data);
|
||||
|
||||
GPUTexture *GPU_texture_create_error(int dimension, bool array);
|
||||
|
||||
void GPU_texture_add_mipmap(GPUTexture *tex,
|
||||
eGPUDataFormat gpu_data_format,
|
||||
int miplvl,
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "BKE_global.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_glew.h"
|
||||
|
@ -239,6 +241,13 @@ bool GPU_crappy_amd_driver(void)
|
|||
return GG.broken_amd_driver;
|
||||
}
|
||||
|
||||
int GPU_texture_size_with_limit(int res)
|
||||
{
|
||||
int size = GPU_max_texture_size();
|
||||
int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
|
||||
return min_ii(reslimit, res);
|
||||
}
|
||||
|
||||
void gpu_extensions_init(void)
|
||||
{
|
||||
/* during 2.8 development each platform has its own OpenGL minimum requirements
|
||||
|
|
|
@ -153,7 +153,6 @@ const struct GPUShaderConfigData GPU_shader_cfg_data[GPU_SHADER_CFG_LEN] = {
|
|||
|
||||
/* cache of built-in shaders (each is created on first use) */
|
||||
static GPUShader *builtin_shaders[GPU_SHADER_CFG_LEN][GPU_SHADER_BUILTIN_LEN] = {{NULL}};
|
||||
static int g_shader_builtin_srgb_transform = 0;
|
||||
|
||||
typedef struct {
|
||||
const char *vert;
|
||||
|
|
|
@ -268,6 +268,12 @@ void GPU_clip_distances(int distances_new)
|
|||
distances_enabled = distances_new;
|
||||
}
|
||||
|
||||
bool GPU_mipmap_enabled(void)
|
||||
{
|
||||
/* TODO(fclem) this used to be a userdef option. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \name GPU Push/Pop State
|
||||
* \{ */
|
||||
|
||||
|
|
|
@ -1118,15 +1118,15 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint
|
|||
return tex;
|
||||
}
|
||||
|
||||
static GLenum convert_target_to_gl(eGPUTextureTarget target)
|
||||
static GLenum convert_target_to_gl(int dimension, bool is_array)
|
||||
{
|
||||
switch (target) {
|
||||
case TEXTARGET_2D:
|
||||
return GL_TEXTURE_2D;
|
||||
case TEXTARGET_2D_ARRAY:
|
||||
return GL_TEXTURE_2D_ARRAY;
|
||||
case TEXTARGET_TILE_MAPPING:
|
||||
return GL_TEXTURE_1D_ARRAY;
|
||||
switch (dimension) {
|
||||
case 1:
|
||||
return is_array ? GL_TEXTURE_1D : GL_TEXTURE_1D_ARRAY;
|
||||
case 2:
|
||||
return is_array ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY;
|
||||
case 3:
|
||||
return GL_TEXTURE_3D;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return GL_TEXTURE_2D;
|
||||
|
@ -1134,9 +1134,9 @@ static GLenum convert_target_to_gl(eGPUTextureTarget target)
|
|||
}
|
||||
|
||||
/* Create an error texture that will bind an invalid texture (pink) at draw time. */
|
||||
GPUTexture *GPU_texture_create_error(eGPUTextureTarget target)
|
||||
GPUTexture *GPU_texture_create_error(int dimension, bool is_array)
|
||||
{
|
||||
GLenum textarget = convert_target_to_gl(target);
|
||||
GLenum textarget = convert_target_to_gl(dimension, is_array);
|
||||
|
||||
GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__);
|
||||
tex->bindcode = 0;
|
||||
|
|
|
@ -23,6 +23,7 @@ set(INC
|
|||
../blenkernel
|
||||
../blenlib
|
||||
../blenloader
|
||||
../gpu
|
||||
../makesdna
|
||||
../makesrna
|
||||
../../../intern/guardedalloc
|
||||
|
@ -63,6 +64,7 @@ set(SRC
|
|||
intern/thumbs_blend.c
|
||||
intern/thumbs_font.c
|
||||
intern/util.c
|
||||
intern/util_gpu.c
|
||||
intern/writeimage.c
|
||||
|
||||
IMB_colormanagement.h
|
||||
|
|
|
@ -88,6 +88,12 @@ struct GSet;
|
|||
struct ImageFormatData;
|
||||
struct Stereo3dFormat;
|
||||
|
||||
/**
|
||||
*
|
||||
* \attention defined in GPU_texture.h
|
||||
*/
|
||||
struct GPUTexture;
|
||||
|
||||
/**
|
||||
*
|
||||
* \attention Defined in allocimbuf.c
|
||||
|
@ -727,6 +733,24 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines,
|
|||
void IMB_ffmpeg_init(void);
|
||||
const char *IMB_ffmpeg_last_error(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* \attention defined in util_gpu.c
|
||||
*/
|
||||
void IMB_gpu_get_format(const struct ImBuf *ibuf,
|
||||
bool high_bitdepth,
|
||||
uint *r_data_format,
|
||||
uint *r_texture_format);
|
||||
void *IMB_gpu_get_data(const struct ImBuf *ibuf,
|
||||
const bool do_rescale,
|
||||
const int rescale_size[2],
|
||||
const bool compress_as_srgb,
|
||||
const bool store_premultiplied,
|
||||
bool *r_freedata);
|
||||
struct GPUTexture *IMB_create_gpu_texture(struct ImBuf *ibuf,
|
||||
bool use_high_bitdepth,
|
||||
bool use_premult);
|
||||
|
||||
/**
|
||||
*
|
||||
* \attention defined in stereoimbuf.c
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* 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) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
* util.c
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup imbuf
|
||||
*/
|
||||
|
||||
#include "imbuf.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "IMB_colormanagement.h"
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
/* gpu ibuf utils */
|
||||
|
||||
void IMB_gpu_get_format(const ImBuf *ibuf,
|
||||
bool high_bitdepth,
|
||||
uint *r_data_format /* eGPUDataFormat */,
|
||||
uint *r_texture_format /* eGPUTextureFormat */)
|
||||
{
|
||||
const bool float_rect = (ibuf->rect_float != NULL);
|
||||
const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
|
||||
!IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
|
||||
high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
|
||||
|
||||
*r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
|
||||
|
||||
if (float_rect) {
|
||||
*r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
|
||||
}
|
||||
else {
|
||||
*r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return false if no suitable format was found. */
|
||||
#ifdef WITH_DDS
|
||||
static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format)
|
||||
{
|
||||
/* For DDS we only support data, scene linear and sRGB. Converting to
|
||||
* different colorspace would break the compression. */
|
||||
const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
|
||||
!IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
|
||||
|
||||
if (ibuf->dds_data.fourcc == FOURCC_DXT1) {
|
||||
*r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT1 : GPU_RGBA8_DXT1;
|
||||
}
|
||||
else if (ibuf->dds_data.fourcc == FOURCC_DXT3) {
|
||||
*r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT3 : GPU_RGBA8_DXT3;
|
||||
}
|
||||
else if (ibuf->dds_data.fourcc == FOURCC_DXT5) {
|
||||
*r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT5 : GPU_RGBA8_DXT5;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Apply colormanagement and scale buffer if needed.
|
||||
* *r_freedata is set to true if the returned buffer need to be manually freed.
|
||||
**/
|
||||
void *IMB_gpu_get_data(const ImBuf *ibuf,
|
||||
const bool do_rescale,
|
||||
const int rescale_size[2],
|
||||
const bool compress_as_srgb,
|
||||
const bool store_premultiplied,
|
||||
bool *r_freedata)
|
||||
{
|
||||
const bool is_float_rect = (ibuf->rect_float != NULL);
|
||||
void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect;
|
||||
|
||||
if (is_float_rect) {
|
||||
/* Float image is already in scene linear colorspace or non-color data by
|
||||
* convention, no colorspace conversion needed. But we do require 4 channels
|
||||
* currently. */
|
||||
if (ibuf->channels != 4 || !store_premultiplied) {
|
||||
data_rect = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
|
||||
*r_freedata = true;
|
||||
|
||||
if (data_rect == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IMB_colormanagement_imbuf_to_float_texture(
|
||||
(float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Byte image is in original colorspace from the file. If the file is sRGB
|
||||
* scene linear, or non-color data no conversion is needed. Otherwise we
|
||||
* compress as scene linear + sRGB transfer function to avoid precision loss
|
||||
* in common cases.
|
||||
*
|
||||
* We must also convert to premultiplied for correct texture interpolation
|
||||
* and consistency with float images. */
|
||||
if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
|
||||
data_rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
|
||||
*r_freedata = true;
|
||||
|
||||
if (data_rect == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Texture storage of images is defined by the alpha mode of the image. The
|
||||
* downside of this is that there can be artifacts near alpha edges. However,
|
||||
* this allows us to use sRGB texture formats and preserves color values in
|
||||
* zero alpha areas, and appears generally closer to what game engines that we
|
||||
* want to be compatible with do. */
|
||||
IMB_colormanagement_imbuf_to_byte_texture(
|
||||
(uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
|
||||
}
|
||||
}
|
||||
|
||||
if (do_rescale) {
|
||||
uint *rect = (is_float_rect) ? NULL : (uint *)data_rect;
|
||||
float *rect_float = (is_float_rect) ? (float *)data_rect : NULL;
|
||||
|
||||
ImBuf *scale_ibuf = IMB_allocFromBuffer(rect, rect_float, ibuf->x, ibuf->y, 4);
|
||||
IMB_scaleImBuf(scale_ibuf, UNPACK2(rescale_size));
|
||||
|
||||
data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect;
|
||||
*r_freedata = true;
|
||||
/* Steal the rescaled buffer to avoid double free. */
|
||||
scale_ibuf->rect_float = NULL;
|
||||
scale_ibuf->rect = NULL;
|
||||
IMB_freeImBuf(scale_ibuf);
|
||||
}
|
||||
return data_rect;
|
||||
}
|
||||
|
||||
GPUTexture *IMB_create_gpu_texture(ImBuf *ibuf, bool use_high_bitdepth, bool use_premult)
|
||||
{
|
||||
GPUTexture *tex = NULL;
|
||||
int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)};
|
||||
bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]);
|
||||
|
||||
#ifdef WITH_DDS
|
||||
if (ibuf->ftype == IMB_FTYPE_DDS) {
|
||||
eGPUTextureFormat compressed_format;
|
||||
if (!IMB_gpu_get_compressed_format(ibuf, &compressed_format)) {
|
||||
fprintf(stderr, "Unable to find a suitable DXT compression,");
|
||||
}
|
||||
else if (do_rescale) {
|
||||
fprintf(stderr, "Unable to load DXT image resolution,");
|
||||
}
|
||||
else if (!is_power_of_2_i(ibuf->x) || !is_power_of_2_i(ibuf->y)) {
|
||||
fprintf(stderr, "Unable to load non-power-of-two DXT image resolution,");
|
||||
}
|
||||
else {
|
||||
tex = GPU_texture_create_compressed(
|
||||
ibuf->x, ibuf->y, ibuf->dds_data.nummipmaps, compressed_format, ibuf->dds_data.data);
|
||||
|
||||
if (tex != NULL) {
|
||||
return tex;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "ST3C support not found,");
|
||||
}
|
||||
}
|
||||
/* Fallback to uncompressed texture. */
|
||||
fprintf(stderr, " falling back to uncompressed.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
eGPUDataFormat data_format;
|
||||
eGPUTextureFormat tex_format;
|
||||
IMB_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
|
||||
|
||||
const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
|
||||
bool freebuf = false;
|
||||
|
||||
void *data = IMB_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
|
||||
|
||||
/* Create Texture. */
|
||||
tex = GPU_texture_create_nD(UNPACK2(size), 0, 2, data, tex_format, data_format, 0, false, NULL);
|
||||
|
||||
GPU_texture_anisotropic_filter(tex, true);
|
||||
|
||||
if (freebuf) {
|
||||
MEM_freeN(data);
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
|
@ -200,7 +200,7 @@ static void rna_Image_gpu_texture_update(Main *UNUSED(bmain),
|
|||
Image *ima = (Image *)ptr->owner_id;
|
||||
|
||||
if (!G.background) {
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
}
|
||||
|
||||
WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
|
||||
|
@ -516,7 +516,7 @@ static void rna_Image_pixels_set(PointerRNA *ptr, const float *values)
|
|||
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_MIPMAP_INVALID;
|
||||
BKE_image_mark_dirty(ima, ibuf);
|
||||
if (!G.background) {
|
||||
GPU_free_image(ima);
|
||||
BKE_image_free_gputextures(ima);
|
||||
}
|
||||
WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
|
||||
}
|
||||
|
|
|
@ -220,7 +220,7 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
|
|||
BKE_imageuser_default(&iuser);
|
||||
iuser.framenr = frame;
|
||||
|
||||
GPUTexture *tex = GPU_texture_from_blender(image, &iuser, NULL, TEXTARGET_2D);
|
||||
GPUTexture *tex = BKE_image_get_gpu_texture(image, &iuser, NULL);
|
||||
|
||||
if (tex == NULL) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Failed to load image texture '%s'", image->id.name + 2);
|
||||
|
@ -246,7 +246,7 @@ static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
|
|||
|
||||
static void rna_Image_gl_free(Image *image)
|
||||
{
|
||||
GPU_free_image(image);
|
||||
BKE_image_free_gputextures(image);
|
||||
|
||||
/* remove the nocollect flag, image is available for garbage collection again */
|
||||
image->flag &= ~IMA_NOCOLLECT;
|
||||
|
|
|
@ -179,6 +179,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
|
|||
# include "BKE_blender.h"
|
||||
# include "BKE_global.h"
|
||||
# include "BKE_idprop.h"
|
||||
# include "BKE_image.h"
|
||||
# include "BKE_main.h"
|
||||
# include "BKE_mesh_runtime.h"
|
||||
# include "BKE_paint.h"
|
||||
|
@ -371,7 +372,7 @@ static void rna_userdef_anisotropic_update(Main *bmain, Scene *scene, PointerRNA
|
|||
|
||||
static void rna_userdef_gl_texture_limit_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
GPU_free_images(bmain);
|
||||
BKE_image_free_all_gputextures(bmain);
|
||||
rna_userdef_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -999,7 +999,7 @@ void wm_draw_update(bContext *C)
|
|||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmWindow *win;
|
||||
|
||||
GPU_free_unused_buffers();
|
||||
BKE_image_free_unused_gpu_textures();
|
||||
|
||||
for (win = wm->windows.first; win; win = win->next) {
|
||||
#ifdef WIN32
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "BKE_font.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_icons.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_keyconfig.h"
|
||||
#include "BKE_lib_remap.h"
|
||||
#include "BKE_main.h"
|
||||
|
@ -575,7 +576,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
|
|||
BKE_subdiv_exit();
|
||||
|
||||
if (opengl_is_init) {
|
||||
GPU_free_unused_buffers();
|
||||
BKE_image_free_unused_gpu_textures();
|
||||
}
|
||||
|
||||
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
|
||||
|
|
Loading…
Reference in New Issue