Texture.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. // Copyright (c) 2008-2022 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Graphics/Graphics.h"
  5. #include "../Graphics/Material.h"
  6. #include "../GraphicsAPI/GraphicsImpl.h"
  7. #include "../IO/FileSystem.h"
  8. #include "../IO/Log.h"
  9. #include "../Resource/ResourceCache.h"
  10. #include "../Resource/XMLFile.h"
  11. #include "../DebugNew.h"
  12. namespace Urho3D
  13. {
  14. static const char* addressModeNames[] =
  15. {
  16. "wrap",
  17. "mirror",
  18. "clamp",
  19. "border",
  20. nullptr
  21. };
  22. static const char* filterModeNames[] =
  23. {
  24. "nearest",
  25. "bilinear",
  26. "trilinear",
  27. "anisotropic",
  28. "nearestanisotropic",
  29. "default",
  30. nullptr
  31. };
  32. Texture::Texture(Context* context) :
  33. ResourceWithMetadata(context),
  34. GPUObject(GetSubsystem<Graphics>())
  35. {
  36. }
  37. Texture::~Texture() = default;
  38. void Texture::SetNumLevels(unsigned levels)
  39. {
  40. if (usage_ > TEXTURE_RENDERTARGET)
  41. requestedLevels_ = 1;
  42. else
  43. requestedLevels_ = levels;
  44. }
  45. void Texture::SetFilterMode(TextureFilterMode mode)
  46. {
  47. filterMode_ = mode;
  48. parametersDirty_ = true;
  49. }
  50. void Texture::SetAddressMode(TextureCoordinate coord, TextureAddressMode mode)
  51. {
  52. addressModes_[coord] = mode;
  53. parametersDirty_ = true;
  54. }
  55. void Texture::SetAnisotropy(unsigned level)
  56. {
  57. anisotropy_ = level;
  58. parametersDirty_ = true;
  59. }
  60. void Texture::SetShadowCompare(bool enable)
  61. {
  62. shadowCompare_ = enable;
  63. parametersDirty_ = true;
  64. }
  65. void Texture::SetBorderColor(const Color& color)
  66. {
  67. borderColor_ = color;
  68. parametersDirty_ = true;
  69. }
  70. void Texture::SetBackupTexture(Texture* texture)
  71. {
  72. backupTexture_ = texture;
  73. }
  74. void Texture::SetMipsToSkip(MaterialQuality quality, int toSkip)
  75. {
  76. if (quality >= QUALITY_LOW && quality < MAX_TEXTURE_QUALITY_LEVELS)
  77. {
  78. mipsToSkip_[quality] = (unsigned)toSkip;
  79. // Make sure a higher quality level does not actually skip more mips
  80. for (int i = 1; i < MAX_TEXTURE_QUALITY_LEVELS; ++i)
  81. {
  82. if (mipsToSkip_[i] > mipsToSkip_[i - 1])
  83. mipsToSkip_[i] = mipsToSkip_[i - 1];
  84. }
  85. }
  86. }
  87. int Texture::GetMipsToSkip(MaterialQuality quality) const
  88. {
  89. return (quality >= QUALITY_LOW && quality < MAX_TEXTURE_QUALITY_LEVELS) ? mipsToSkip_[quality] : 0;
  90. }
  91. int Texture::GetLevelWidth(unsigned level) const
  92. {
  93. if (level > levels_)
  94. return 0;
  95. return Max(width_ >> level, 1);
  96. }
  97. int Texture::GetLevelHeight(unsigned level) const
  98. {
  99. if (level > levels_)
  100. return 0;
  101. return Max(height_ >> level, 1);
  102. }
  103. int Texture::GetLevelDepth(unsigned level) const
  104. {
  105. if (level > levels_)
  106. return 0;
  107. return Max(depth_ >> level, 1);
  108. }
  109. unsigned Texture::GetDataSize(int width, int height) const
  110. {
  111. if (IsCompressed())
  112. return GetRowDataSize(width) * ((height + 3) >> 2u);
  113. else
  114. return GetRowDataSize(width) * height;
  115. }
  116. unsigned Texture::GetDataSize(int width, int height, int depth) const
  117. {
  118. return depth * GetDataSize(width, height);
  119. }
  120. unsigned Texture::GetComponents() const
  121. {
  122. if (!width_ || IsCompressed())
  123. return 0;
  124. else
  125. return GetRowDataSize(width_) / width_;
  126. }
  127. void Texture::SetParameters(XMLFile* file)
  128. {
  129. if (!file)
  130. return;
  131. XMLElement rootElem = file->GetRoot();
  132. SetParameters(rootElem);
  133. }
  134. void Texture::SetParameters(const XMLElement& element)
  135. {
  136. LoadMetadataFromXML(element);
  137. for (XMLElement paramElem = element.GetChild(); paramElem; paramElem = paramElem.GetNext())
  138. {
  139. String name = paramElem.GetName();
  140. if (name == "address")
  141. {
  142. String coord = paramElem.GetAttributeLower("coord");
  143. if (coord.Length() >= 1)
  144. {
  145. auto coordIndex = (TextureCoordinate)(coord[0] - 'u');
  146. String mode = paramElem.GetAttributeLower("mode");
  147. SetAddressMode(coordIndex, (TextureAddressMode)GetStringListIndex(mode.CString(), addressModeNames, ADDRESS_WRAP));
  148. }
  149. }
  150. if (name == "border")
  151. SetBorderColor(paramElem.GetColor("color"));
  152. if (name == "filter")
  153. {
  154. String mode = paramElem.GetAttributeLower("mode");
  155. SetFilterMode((TextureFilterMode)GetStringListIndex(mode.CString(), filterModeNames, FILTER_DEFAULT));
  156. if (paramElem.HasAttribute("anisotropy"))
  157. SetAnisotropy(paramElem.GetU32("anisotropy"));
  158. }
  159. if (name == "mipmap")
  160. SetNumLevels(paramElem.GetBool("enable") ? 0 : 1);
  161. if (name == "quality")
  162. {
  163. if (paramElem.HasAttribute("low"))
  164. SetMipsToSkip(QUALITY_LOW, paramElem.GetI32("low"));
  165. if (paramElem.HasAttribute("med"))
  166. SetMipsToSkip(QUALITY_MEDIUM, paramElem.GetI32("med"));
  167. if (paramElem.HasAttribute("medium"))
  168. SetMipsToSkip(QUALITY_MEDIUM, paramElem.GetI32("medium"));
  169. if (paramElem.HasAttribute("high"))
  170. SetMipsToSkip(QUALITY_HIGH, paramElem.GetI32("high"));
  171. }
  172. if (name == "srgb")
  173. SetSRGB(paramElem.GetBool("enable"));
  174. }
  175. }
  176. void Texture::SetParametersDirty()
  177. {
  178. parametersDirty_ = true;
  179. }
  180. void Texture::SetLevelsDirty()
  181. {
  182. if (usage_ == TEXTURE_RENDERTARGET && levels_ > 1)
  183. levelsDirty_ = true;
  184. }
  185. unsigned Texture::CheckMaxLevels(int width, int height, unsigned requestedLevels)
  186. {
  187. unsigned maxLevels = 1;
  188. while (width > 1 || height > 1)
  189. {
  190. ++maxLevels;
  191. width = width > 1 ? (width >> 1u) : 1;
  192. height = height > 1 ? (height >> 1u) : 1;
  193. }
  194. if (!requestedLevels || maxLevels < requestedLevels)
  195. return maxLevels;
  196. else
  197. return requestedLevels;
  198. }
  199. unsigned Texture::CheckMaxLevels(int width, int height, int depth, unsigned requestedLevels)
  200. {
  201. unsigned maxLevels = 1;
  202. while (width > 1 || height > 1 || depth > 1)
  203. {
  204. ++maxLevels;
  205. width = width > 1 ? (width >> 1u) : 1;
  206. height = height > 1 ? (height >> 1u) : 1;
  207. depth = depth > 1 ? (depth >> 1u) : 1;
  208. }
  209. if (!requestedLevels || maxLevels < requestedLevels)
  210. return maxLevels;
  211. else
  212. return requestedLevels;
  213. }
  214. void Texture::CheckTextureBudget(StringHash type)
  215. {
  216. auto* cache = GetSubsystem<ResourceCache>();
  217. unsigned long long textureBudget = cache->GetMemoryBudget(type);
  218. unsigned long long textureUse = cache->GetMemoryUse(type);
  219. if (!textureBudget)
  220. return;
  221. // If textures are over the budget, they likely can not be freed directly as materials still refer to them.
  222. // Therefore free unused materials first
  223. if (textureUse > textureBudget)
  224. cache->ReleaseResources(Material::GetTypeStatic());
  225. }
  226. void Texture::SetSRGB(bool enable)
  227. {
  228. GAPI gapi = Graphics::GetGAPI();
  229. #ifdef URHO3D_OPENGL
  230. if (gapi == GAPI_OPENGL)
  231. return SetSRGB_OGL(enable);
  232. #endif
  233. #ifdef URHO3D_D3D11
  234. if (gapi == GAPI_D3D11)
  235. return SetSRGB_D3D11(enable);
  236. #endif
  237. }
  238. void Texture::UpdateParameters()
  239. {
  240. GAPI gapi = Graphics::GetGAPI();
  241. #ifdef URHO3D_OPENGL
  242. if (gapi == GAPI_OPENGL)
  243. return UpdateParameters_OGL();
  244. #endif
  245. #ifdef URHO3D_D3D11
  246. if (gapi == GAPI_D3D11)
  247. return UpdateParameters_D3D11();
  248. #endif
  249. }
  250. bool Texture::GetParametersDirty() const
  251. {
  252. GAPI gapi = Graphics::GetGAPI();
  253. #ifdef URHO3D_OPENGL
  254. if (gapi == GAPI_OPENGL)
  255. return GetParametersDirty_OGL();
  256. #endif
  257. #ifdef URHO3D_D3D11
  258. if (gapi == GAPI_D3D11)
  259. return GetParametersDirty_D3D11();
  260. #endif
  261. return {}; // Prevent warning
  262. }
  263. bool Texture::IsCompressed() const
  264. {
  265. GAPI gapi = Graphics::GetGAPI();
  266. #ifdef URHO3D_OPENGL
  267. if (gapi == GAPI_OPENGL)
  268. return IsCompressed_OGL();
  269. #endif
  270. #ifdef URHO3D_D3D11
  271. if (gapi == GAPI_D3D11)
  272. return IsCompressed_D3D11();
  273. #endif
  274. return {}; // Prevent warning
  275. }
  276. unsigned Texture::GetRowDataSize(int width) const
  277. {
  278. GAPI gapi = Graphics::GetGAPI();
  279. #ifdef URHO3D_OPENGL
  280. if (gapi == GAPI_OPENGL)
  281. return GetRowDataSize_OGL(width);
  282. #endif
  283. #ifdef URHO3D_D3D11
  284. if (gapi == GAPI_D3D11)
  285. return GetRowDataSize_D3D11(width);
  286. #endif
  287. return {}; // Prevent warning
  288. }
  289. void Texture::RegenerateLevels()
  290. {
  291. GAPI gapi = Graphics::GetGAPI();
  292. #ifdef URHO3D_OPENGL
  293. if (gapi == GAPI_OPENGL)
  294. return RegenerateLevels_OGL();
  295. #endif
  296. #ifdef URHO3D_D3D11
  297. if (gapi == GAPI_D3D11)
  298. return RegenerateLevels_D3D11();
  299. #endif
  300. }
  301. }