Welcome to mirror list, hosted at ThFree Co, Russian Federation.

draw_texture_pool.cc « intern « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b54df9284186fcdfdb71d83db31ea4de506ff9bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* SPDX-License-Identifier: GPL-2.0-or-later
 * Copyright 2021 Blender Foundation. */

/** \file
 * \ingroup draw
 */

#include "BKE_global.h"

#include "BLI_vector.hh"

#include "draw_texture_pool.h"

using namespace blender;

struct DRWTexturePoolHandle {
  uint64_t users_bits;
  GPUTexture *texture;
};

struct DRWTexturePool {
  Vector<void *, 16> users;
  Vector<DRWTexturePoolHandle> handles;
  /* Cache last result to avoid linear search each time. */
  int last_user_id = -1;
};

DRWTexturePool *DRW_texture_pool_create()
{
  return new DRWTexturePool();
}

void DRW_texture_pool_free(DRWTexturePool *pool)
{
  /* Resetting the pool twice will effectively free all textures. */
  DRW_texture_pool_reset(pool);
  DRW_texture_pool_reset(pool);
  delete pool;
}

GPUTexture *DRW_texture_pool_query(
    DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user)
{
  int user_id = pool->last_user_id;
  /* Try cached value. */
  if (user_id != -1) {
    if (pool->users[user_id] != user) {
      user_id = -1;
    }
  }
  /* Try to find inside previous users. */
  if (user_id == -1) {
    user_id = pool->users.first_index_of_try(user);
  }
  /* No chance, needs to add it to the user list. */
  if (user_id == -1) {
    user_id = pool->users.size();
    pool->users.append(user);
    /* If there is more than 63 users, better refactor this system. */
    BLI_assert(user_id < 64);
  }
  pool->last_user_id = user_id;

  uint64_t user_bit = 1llu << user_id;
  for (DRWTexturePoolHandle &handle : pool->handles) {
    /* Skip if the user is already using this texture. */
    if (user_bit & handle.users_bits) {
      continue;
    }
    /* If everything matches reuse the texture. */
    if ((GPU_texture_format(handle.texture) == format) &&
        (GPU_texture_width(handle.texture) == width) &&
        (GPU_texture_height(handle.texture) == height)) {
      handle.users_bits |= user_bit;
      return handle.texture;
    }
  }

  char name[16] = "DRW_tex_pool";
  if (G.debug & G_DEBUG_GPU) {
    int texture_id = pool->handles.size();
    SNPRINTF(name, "DRW_tex_pool_%d", texture_id);
  }

  DRWTexturePoolHandle handle;
  handle.users_bits = user_bit;
  handle.texture = GPU_texture_create_2d(name, width, height, 1, format, nullptr);
  pool->handles.append(handle);
  /* Doing filtering for depth does not make sense when not doing shadow mapping,
   * and enabling texture filtering on integer texture make them unreadable. */
  bool do_filter = !GPU_texture_depth(handle.texture) && !GPU_texture_integer(handle.texture);
  GPU_texture_filter_mode(handle.texture, do_filter);

  return handle.texture;
}

void DRW_texture_pool_reset(DRWTexturePool *pool)
{
  pool->last_user_id = -1;

  for (auto it = pool->handles.rbegin(); it != pool->handles.rend(); ++it) {
    DRWTexturePoolHandle &handle = *it;
    if (handle.users_bits == 0) {
      if (handle.texture) {
        GPU_texture_free(handle.texture);
        handle.texture = nullptr;
      }
    }
    else {
      handle.users_bits = 0;
    }
  }

  /* Reverse iteration to make sure we only reorder with known good handles. */
  for (int i = pool->handles.size() - 1; i >= 0; i--) {
    if (!pool->handles[i].texture) {
      pool->handles.remove_and_reorder(i);
    }
  }
}