Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/intern/gpu_draw.c
| Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
| #include "GPU_draw.h" | #include "GPU_draw.h" | ||||
| #include "GPU_extensions.h" | #include "GPU_extensions.h" | ||||
| #include "GPU_glew.h" | #include "GPU_glew.h" | ||||
| #include "GPU_platform.h" | #include "GPU_platform.h" | ||||
| #include "GPU_texture.h" | #include "GPU_texture.h" | ||||
| #include "PIL_time.h" | #include "PIL_time.h" | ||||
| static void gpu_free_image_immediate(Image *ima); | static void gpu_free_image(Image *ima, const bool immediate); | ||||
| static void gpu_free_unused_buffers(void); | |||||
| //* Checking powers of two for images since OpenGL ES requires it */ | //* Checking powers of two for images since OpenGL ES requires it */ | ||||
| #ifdef WITH_DDS | #ifdef WITH_DDS | ||||
| static bool is_power_of_2_resolution(int w, int h) | static bool is_power_of_2_resolution(int w, int h) | ||||
| { | { | ||||
| return is_power_of_2_i(w) && is_power_of_2_i(h); | return is_power_of_2_i(w) && is_power_of_2_i(h); | ||||
| } | } | ||||
| #endif | #endif | ||||
| ▲ Show 20 Lines • Show All 782 Lines • ▼ Show 20 Lines | |||||
| * available. It is also required when requesting the GPUTexture for a render result. */ | * available. It is also required when requesting the GPUTexture for a render result. */ | ||||
| GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, int textarget) | GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, int textarget) | ||||
| { | { | ||||
| #ifndef GPU_STANDALONE | #ifndef GPU_STANDALONE | ||||
| if (ima == NULL) { | if (ima == NULL) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* Free any unused GPU textures, since we know we are in a thread with OpenGL | |||||
| * context and might as well ensure we have as much space free as possible. */ | |||||
| gpu_free_unused_buffers(); | |||||
| /* currently, gpu refresh tagging is used by ima sequences */ | /* currently, gpu refresh tagging is used by ima sequences */ | ||||
| if (ima->gpuflag & IMA_GPU_REFRESH) { | if (ima->gpuflag & IMA_GPU_REFRESH) { | ||||
| gpu_free_image_immediate(ima); | gpu_free_image(ima, true); | ||||
| ima->gpuflag &= ~IMA_GPU_REFRESH; | ima->gpuflag &= ~IMA_GPU_REFRESH; | ||||
| } | } | ||||
| /* Tag as in active use for garbage collector. */ | /* Tag as in active use for garbage collector. */ | ||||
| BKE_image_tag_time(ima); | BKE_image_tag_time(ima); | ||||
| /* Test if we already have a texture. */ | /* Test if we already have a texture. */ | ||||
| GPUTexture **tex = gpu_get_image_gputexture(ima, textarget, iuser ? iuser->multiview_eye : 0); | GPUTexture **tex = gpu_get_image_gputexture(ima, textarget, iuser ? iuser->multiview_eye : 0); | ||||
| ▲ Show 20 Lines • Show All 460 Lines • ▼ Show 20 Lines | #ifndef GPU_STANDALONE | ||||
| if (tex != NULL) { | if (tex != NULL) { | ||||
| gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h); | gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h); | ||||
| } | } | ||||
| BKE_image_release_ibuf(ima, ibuf, NULL); | BKE_image_release_ibuf(ima, ibuf, NULL); | ||||
| #endif | #endif | ||||
| } | } | ||||
| static LinkNode *image_free_queue = NULL; | /* Delayed GPU texture free. Image datablocks can be deleted by any thread, | ||||
| static ThreadMutex img_queue_mutex = BLI_MUTEX_INITIALIZER; | * 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_queue_image_for_free(Image *ima) | static void gpu_free_unused_buffers() | ||||
| { | { | ||||
| BLI_mutex_lock(&img_queue_mutex); | if (gpu_texture_free_queue == NULL) { | ||||
| BLI_linklist_prepend(&image_free_queue, ima); | |||||
| BLI_mutex_unlock(&img_queue_mutex); | |||||
| } | |||||
| void GPU_free_unused_buffers(Main *bmain) | |||||
| { | |||||
| if (!BLI_thread_is_main()) { | |||||
| return; | return; | ||||
| } | } | ||||
| BLI_mutex_lock(&img_queue_mutex); | BLI_mutex_lock(&gpu_texture_queue_mutex); | ||||
| /* images */ | |||||
| for (LinkNode *node = image_free_queue; node; node = node->next) { | |||||
| Image *ima = node->link; | |||||
| /* check in case it was freed in the meantime */ | if (gpu_texture_free_queue != NULL) { | ||||
| if (bmain && BLI_findindex(&bmain->images, ima) != -1) { | for (LinkNode *node = gpu_texture_free_queue; node; node = node->next) { | ||||
| GPU_free_image(ima); | GPUTexture *tex = node->link; | ||||
| } | GPU_texture_free(tex); | ||||
| } | } | ||||
| BLI_linklist_free(image_free_queue, NULL); | BLI_linklist_free(gpu_texture_free_queue, NULL); | ||||
| image_free_queue = NULL; | gpu_texture_free_queue = NULL; | ||||
| } | |||||
| BLI_mutex_unlock(&img_queue_mutex); | BLI_mutex_unlock(&gpu_texture_queue_mutex); | ||||
| } | } | ||||
| static void gpu_free_image_immediate(Image *ima) | static void gpu_free_image(Image *ima, const bool immediate) | ||||
| { | { | ||||
| for (int eye = 0; eye < 2; eye++) { | for (int eye = 0; eye < 2; eye++) { | ||||
| for (int i = 0; i < TEXTARGET_COUNT; i++) { | for (int i = 0; i < TEXTARGET_COUNT; i++) { | ||||
| /* free glsl image binding */ | |||||
| if (ima->gputexture[i][eye] != NULL) { | if (ima->gputexture[i][eye] != NULL) { | ||||
| if (immediate) { | |||||
| GPU_texture_free(ima->gputexture[i][eye]); | 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->gputexture[i][eye] = NULL; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; | ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; | ||||
| } | } | ||||
| void GPU_free_image(Image *ima) | void GPU_free_unused_buffers() | ||||
| { | { | ||||
| if (!BLI_thread_is_main()) { | if (BLI_thread_is_main()) { | ||||
| gpu_queue_image_for_free(ima); | gpu_free_unused_buffers(); | ||||
| return; | } | ||||
| } | } | ||||
| gpu_free_image_immediate(ima); | void GPU_free_image(Image *ima) | ||||
| { | |||||
| gpu_free_image(ima, BLI_thread_is_main()); | |||||
| } | } | ||||
| void GPU_free_images(Main *bmain) | void GPU_free_images(Main *bmain) | ||||
| { | { | ||||
| if (bmain) { | if (bmain) { | ||||
| for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { | for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { | ||||
| GPU_free_image(ima); | GPU_free_image(ima); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 52 Lines • Show Last 20 Lines | |||||